Add performance class module, update make

This commit is contained in:
Lamdonn 2024-10-21 01:19:11 +08:00
parent 81db585502
commit ca9bdaad24
5 changed files with 1149 additions and 10 deletions

View File

@ -1,8 +1,9 @@
##################################################################################
### config
##################################################################################
CC = gcc
AR = ar
CC := gcc
AR := ar
CSTD := c11
BUILT_DIR = built
TARGET = app
LIB = varch
@ -18,18 +19,18 @@ VSTD_PATH = $(WORKSPACE)/02_vstd
CONTAINER_PATH = $(WORKSPACE)/03_container
ALGORITHM_PATH = $(WORKSPACE)/04_algorithm
PARSER_PATH = $(WORKSPACE)/05_parser
PERFORMANCE_PATH = $(WORKSPACE)/06_performance
##################################################################################
### sources and head path
### sources, libaries and head path
##################################################################################
include $(TESTSPACE)/test.mk
INCLUDE += $(APPLICATION_PATH)
INCLUDE += $(GENDATA_PATH)
INCLUDE += $(VSTD_PATH)
INCLUDE += $(CONTAINER_PATH)
INCLUDE += $(ALGORITHM_PATH)
INCLUDE += $(PARSER_PATH)
INCLUDE += $(PERFORMANCE_PATH)
LIBSRCS += $(APPLICATION_PATH)/init.c
LIBSRCS += $(wildcard $(APPLICATION_PATH)/console/*.c)
@ -38,14 +39,30 @@ LIBSRCS += $(wildcard $(VSTD_PATH)/*.c)
LIBSRCS += $(wildcard $(CONTAINER_PATH)/*.c)
LIBSRCS += $(wildcard $(ALGORITHM_PATH)/*.c)
LIBSRCS += $(wildcard $(PARSER_PATH)/*.c)
LIBSRCS += $(wildcard $(PERFORMANCE_PATH)/*.c)
LIBLIST += m
LIBLIST += pthread
# LIBLIST += X11
CFLAG += -std=$(CSTD)
# CFLAG += -Wall
# CFLAG += -Werror
##################################################################################
### test source
##################################################################################
include $(TESTSPACE)/test.mk
TESTSRC += $(APPLICATION_PATH)/main.c
TESTSRC += $(TEST_SRC)
##################################################################################
### targets and recipes
### recipes
##################################################################################
INCS = $(addprefix -I,$(INCLUDE))
LIBS = $(addprefix -l,$(LIBLIST))
OBJP = $(BUILT_DIR)/obj
BINP = $(BUILT_DIR)/bin
LIBO = $(patsubst %.c, $(OBJP)/%.o, $(LIBSRCS))
@ -56,17 +73,55 @@ LIBN = lib$(LIB)
LIBA = $(BUILT_DIR)/$(LIBN).a
LIBP ?= /usr
##################################################################################
### make targets
##################################################################################
# link
${TARP}:$(OBJS)
mkdir -p $(dir $@)
# @ $(CC) $(OBJS) -o $(TARP) -lm -lX11 -lpthread
@ $(CC) $(CFLAG) $(OBJS) -o $(TARP) -lm -lpthread
@ $(CC) $(CFLAG) $(OBJS) -o $(TARP) $(LIBS)
# compile
$(OBJP)/%.o:%.c
@ mkdir -p $(dir $@)
@ echo "compiling $(notdir $<)"
@ $(CC) $(CFLAG) $(INCS) -c $< -o $@
app:${TARP}
# lib
lib:$(LIBO)
@ $(AR) -crv $(LIBA) $(LIBO)
.PHONY:help
help:
@echo "Makefile Help"
@echo "Usage: make [target] [options]"
@echo ""
@echo "Available targets:"
@echo ""
@echo " app - Build the project (default target $(TARP))"
@echo " [CC] - Specify the compiler (default is $(CC))"
@echo " [AR] - Specify the archiver (default is $(AR))"
@echo " [CSTD] - Specify the C std version (c89, c99, c11, c18, default is $(CSTD))"
@echo ""
@echo " lib - Build the library ($(LIB))"
@echo ""
@echo " run - Execute the default application"
@echo ""
@echo " install - Install the library"
@echo " [LIBP] - Specify the lib installation path (default is $(LIBP))"
@echo " example: linux - make install"
@echo " MinGW - make install LIBP=D:/MinGW"
@echo ""
@echo " uninstall - Uninstall the library"
@echo " [LIBP] - Same as install"
@echo ""
@echo " clean - Remove build artifacts"
@echo ""
@echo " help - Show this help message"
.PHONY:clean
clean:
@ -74,9 +129,13 @@ clean:
@ rm $(BUILT_DIR)/$(WORKSPACE) -rf
@ rm $(BUILT_DIR)/* -rf
.PHONY:run
run:app
@ echo "executing..."
./$(BUILT_DIR)/bin/$(TARGET)
.PHONY:install
install:$(LIBO)
@ $(AR) -crv $(LIBA) $(LIBO)
install:lib
@ mkdir -p $(LIBP)/include/$(LIB)
@ find $(INCLUDE) -name "*.h" -exec cp {} $(LIBP)/include/$(LIB) \;
@ mv -f $(LIBA) $(LIBP)/lib \

View File

@ -0,0 +1,389 @@
/*********************************************************************************************************
* ------------------------------------------------------------------------------------------------------
* 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;
}
}
}

View File

@ -0,0 +1,87 @@
/*********************************************************************************************************
* ------------------------------------------------------------------------------------------------------
* file description
* ------------------------------------------------------------------------------------------------------
* \file ramt.h
* \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.
********************************************************************************************************/
#ifndef __ramt_H
#define __ramt_H
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* Version infomation */
#define RAMT_V_MAJOR 0
#define RAMT_V_MINOR 1
#define RAMT_V_REVISE 0
// Define different RAM test modes
#define RAMT_MODE_NORMAL ((uint32_t)0x00000001) // Normal read/write test
#define RAMT_MODE_BOUNDARY ((uint32_t)0x00000002) // Boundary test
#define RAMT_MODE_PATTERN ((uint32_t)0x00000004) // Data pattern test
#define RAMT_MODE_RANDOM ((uint32_t)0x00000008) // Random access test
#define RAMT_MODE_INVERSION ((uint32_t)0x00000010) // Inversion test
#define RAMT_MODE_CLEARING ((uint32_t)0x00000020) // Clearing test
#define RAMT_MODE_SPECIFIC ((uint32_t)0x00000040) // Specific data test
// RAM structure definition
typedef struct
{
void *base; // Pointer to the simulated RAM
uint32_t size; // Size of the RAM
uint32_t private[4]; // Private data, modification not allowed
} RAMT;
/**
* \brief Initialize RAMT structure
* \param[in] ramt: Pointer to the RAMT structure to be initialized
* \return 1 if initialization is successful, 0 if it fails
*/
int ramt_init(RAMT *ramt);
/**
* \brief Start the RAM testing with specified mode and duration
* \param[in] ramt: Pointer to the RAMT structure
* \param[in] mode: The mode of the RAM test, see RAMT_MODE_XXX define
* \param[in] duration: The duration for which the RAM test should run, 0xFFFFFFFF continuous running
* \return 1 if the operation is successful, 0 if it fails
*/
int ramt_start(RAMT *ramt, uint32_t mode, uint32_t duration);
/**
* \brief Stop the RAM testing
* \param[in] ramt: Pointer to the RAMT structure
* \return 1 if the operation is successful, 0 if it fails
*/
int ramt_stop(RAMT *ramt);
/**
* \brief Retrieve the historical result of the RAM test
* \param[in] ramt: Pointer to the RAMT structure
* \return The result history if successful, 0xFFFFFFFF if it invalid, fail mask see RAMT_MODE_XXX define
*/
uint32_t ramt_result(RAMT *ramt);
/**
* \brief Retrieve the latest result of the RAM test
* \param[in] ramt: Pointer to the RAMT structure
* \return The latest result if successful, 0xFFFFFFFF if it invalid, fail mask see RAMT_MODE_XXX define
*/
uint32_t ramt_result_latest(RAMT *ramt);
/**
* \brief Periodically execute RAM testing tasks based on the mode and duration
* \param[in] ramt: Pointer to the RAMT structure
*/
void ramt_task(RAMT *ramt);
#endif

View File

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

View File

@ -0,0 +1,135 @@
/*********************************************************************************************************
* ------------------------------------------------------------------------------------------------------
* file description
* ------------------------------------------------------------------------------------------------------
* \file romt.h
* \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.
********************************************************************************************************/
#ifndef __romt_H
#define __romt_H
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/* Version infomation */
#define ROMT_V_MAJOR 0
#define ROMT_V_MINOR 1
#define ROMT_V_REVISE 0
#define ROMT_MODE_READ ((uint32_t)0x00000001) ///< Mode for reading from ROM
#define ROMT_MODE_WRITE ((uint32_t)0x00000002) ///< Mode for writing to ROM
#define ROMT_MODE_NORMAL ((uint32_t)0x00000004) ///< Normal operation mode
#define ROMT_MODE_BOUNDARY ((uint32_t)0x00000008) ///< Boundary condition mode
#define ROMT_MODE_RANDOM ((uint32_t)0x00000010) ///< Random access mode
#define ROMT_MODE_PATTERN ((uint32_t)0x00000020) ///< Pattern generation mode
#define UNIT_SIZE ((uint16_t)256) ///< Size of a unit data block
/**
* \brief Type definition for read callback function.
* \param[in] address: Address from which to read data.
* \param[in] data: Pointer to the buffer where data will be stored.
* \param[in] length: Number of bytes to read.
* \return Returns the number of bytes read on success; otherwise, an error code.
*/
typedef int (*romt_read_t)(uint32_t address, const uint8_t *data, uint32_t length);
/**
* \brief Type definition for write callback function.
* \param[in] address: Address at which to write data.
* \param[in] data: Pointer to the buffer containing data to be written.
* \param[in] length: Number of bytes to write.
* \return Returns the number of bytes written on success; otherwise, an error code.
*/
typedef int (*romt_write_t)(uint32_t address, const uint8_t *data, uint32_t length);
// ROM structure definition
typedef struct
{
uint32_t base; ///< Pointer to the simulated ROM
uint32_t size; ///< Size of the ROM
romt_read_t read; ///< Read function pointer
romt_write_t write; ///< Write function pointer
uint32_t private[4]; ///< Private data, modification not allowed
} ROMT;
/**
* \brief Initialize the ROMT structure.
*
* This function checks the validity of the provided ROMT structure and its parameters,
* and initializes the private data field to zero. It ensures that the size, read, and
* write function pointers are valid before proceeding with the initialization.
*
* \param[in] romt: Pointer to the ROMT structure to be initialized.
* \return Returns 1 if initialization is successful; otherwise, returns 0.
*/
int romt_init(ROMT *romt);
/**
* \brief Start the ROMT operations with specified mode and duration.
*
* This function initializes the ROMT structure for operation by setting the test mode
* and duration. It checks the validity of the input parameters and ensures that the ROM
* is properly initialized before starting the operation.
*
* \param[in] romt: Pointer to the ROMT structure to be started.
* \param[in] mode: The mode of operation for the ROMT.
* \param[in] duration: The duration for which the operation should run.
* \return Returns 1 if the operation is successful; otherwise, returns 0.
*/
int romt_start(ROMT *romt, uint32_t mode, uint32_t duration);
/**
* \brief Stop the ROMT operations and reset its configuration.
*
* This function halts the operation of the ROMT structure and resets the test mode
* and duration to zero. It ensures that the ROM is properly initialized before stopping
* the operation.
*
* \param[in] romt: Pointer to the ROMT structure to be stopped.
* \return Returns 1 if the operation is successful; otherwise, returns 0.
*/
int romt_stop(ROMT *romt);
/**
* \brief Retrieve the historical result from the ROMT structure.
*
* This function checks the validity of the ROMT structure and returns the historical
* result stored in the private data. If any checks fail, it returns 0xFFFFFFFF
* to indicate an error.
*
* \param[in] romt: Pointer to the ROMT structure from which to retrieve the result.
* \return Returns the historical result if successful; otherwise, returns 0xFFFFFFFF.
*/
uint32_t romt_result(ROMT *romt);
/**
* \brief Retrieve the latest result from the ROMT structure.
*
* This function checks the validity of the ROMT structure and returns the latest
* result stored in the private data. If any checks fail, it returns 0xFFFFFFFF
* to indicate an error.
*
* \param[in] romt: Pointer to the ROMT structure from which to retrieve the result.
* \return Returns the latest result if successful; otherwise, returns 0xFFFFFFFF.
*/
uint32_t romt_result_latest(ROMT *romt);
/**
* \brief Execute the ROMT test tasks based on the configured test mode.
*
* This function checks the current test mode and performs the respective tests (read, write,
* normal, boundary, random, pattern) on the ROMT structure if the duration allows for it.
* It updates the latest result and accumulates the historical result in the private data.
*
* \param[in] romt: Pointer to the ROMT structure to be tested.
*/
void romt_task(ROMT *romt);
#endif