Added a small, automated test file for the core memory functions.

This commit is contained in:
lephe 2018-08-23 22:32:52 +02:00
parent 262ba283ac
commit 0c9ee5f4f8
4 changed files with 237 additions and 16 deletions

View File

@ -28,5 +28,12 @@ SECTIONS
_bdata = . ;
*(.data);
_edata = . ;
/* Provide a default */
_end = . ;
} > ram
/DISCARD/ : {
*(.eh_frame)
}
}

View File

@ -3,12 +3,14 @@ extern "C" {
#endif
#include "string.h"
#include "fxlib.h"
#include "fxlib.h"
#ifdef __cplusplus
}
#endif
#include "memfunctest.h"
// unused
void conv_to_hex(char x, char* a, char* b) {
*a = (x >> 4) & 0xf;
@ -34,25 +36,26 @@ int main(void) {
//char* out;
char out[20] = {0};
while (1) {
Bdisp_AllClr_DD();
Bdisp_AllClr_DD();
locate(1, 1);
Print((unsigned char*) in);
locate(1, 1);
Print((unsigned char*) in);
//out = (char*) malloc(strlen(in) + 1);
strcpy(out, in);
locate(1, 2);
Print((unsigned char*) out);
//free(out);
//out = (char*) malloc(strlen(in) + 1);
strcpy(out, in);
locate(1, 2);
Print((unsigned char*) out);
//free(out);
Bdisp_PutDisp_DD();
GetKey(&key);
}
locate(1, 3);
memfunctest();
return 0;
Bdisp_PutDisp_DD();
while(1) GetKey(&key);
return 0;
}
void initialize(void) {
main();
}
}

194
src/memfunctest.c Normal file
View File

@ -0,0 +1,194 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
/* 4-abyte buffer alignement */
#define ALIGN(n) __attribute__((aligned(n)))
/* Unused parameters */
#define UNUSED __attribute__((unused))
//---
// Basic setup
//---
/* Source buffer, used as a data source when copying */
ALIGN(4) static uint8_t src[256];
/* Destination buffer, used as destination when copying or clearing */
ALIGN(4) static uint8_t dst[256];
/* System buffer, used to reproduce the behavior on the system and compare */
ALIGN(4) static uint8_t sys[256];
/* Temporary buffer, used by the naive memmove() */
ALIGN(4) static uint8_t tmp[256];
/* fill() - fill a buffer with non-zero data */
static void fill(uint8_t *buf)
{
for(int i = 0; i < 256; i++) buf[i] = i;
}
/* clear() - clear a buffer with zeros */
static void clear(uint8_t *buf)
{
for(int i = 0; i < 256; i++) buf[i] = 0;
}
/* cmp() - check that some two buffers are equal
Returns non-zero if the buffers differ. */
static int cmp(uint8_t *lft, uint8_t *rgt)
{
for(int i = 0; i < 256; i++) if(lft[i] != rgt[i]) return 1;
return 0;
}
//---
// Naive functions (reference behaviour)
//---
/* naive_memcpy() - bytewise copy */
static void *naive_memcpy(void *_dst, const void *_src, size_t len)
{
uint8_t *dst = _dst;
uint8_t const *src = _src;
while(len--) *dst++ = *src++;
return _dst;
}
/* naive_memset() - bytewise set */
static void *naive_memset(void *_dst, int byte, size_t len)
{
uint8_t *dst = _dst;
while(len--) *dst++ = byte;
return _dst;
}
/* naive_memmove() - bytewise copy with buffer */
static void *naive_memmove(void *_dst, const void *_src, size_t len)
{
naive_memcpy(tmp, _src, len);
naive_memcpy(_dst, tmp, len);
return _dst;
}
//---
// Testing functions
//---
static int test_memcpy(int off_dst, int off_src, size_t len)
{
clear(dst);
clear(sys);
memcpy(dst + off_dst, src + off_src, len);
naive_memcpy(sys + off_dst, src + off_src, len);
return cmp(dst, sys);
}
static int test_memset(int off_dst, UNUSED int off_src, size_t len)
{
fill(dst);
fill(sys);
memset(dst + off_dst, 0, len);
naive_memset(sys + off_dst, 0, len);
return cmp(dst, sys);
}
static int test_memmove(int off_dst, int off_src, size_t len)
{
fill(dst);
fill(sys);
memmove(dst + off_dst, dst + off_src, len);
naive_memmove(sys + off_dst, sys + off_src, len);
return cmp(dst, sys);
}
//---
// Automated tests
//
// These tests are meant to check all size/alignment scenarios for the
// core memory functions. Two intervals of sizes are tested:
// - 12..15 bytes, expected to be handled naively
// - 192..195 bytes, expected to trigger alignment-related optimizations
// For each of these intervals, all alignments possibilities are tested:
// - 4n + { 0,1,2,3 } for the source address
// - 4n + { 0,1,2,3 } for destination address
// Also, the source and destination regions are made to overlap to allow
// non-trivial memmove() cases to be checked.
//
// The testing function non-zero if one or more tests fail.
//---
/* test() - check core memory functions in various size/alignment scenarios
The function to test takes three arguments: two buffer offsets and the size
of the operation. Bounds need no be checked. It must return 0 in case of
success and non-zero in case of failure.
@func Function to test, will be called with various sizes and alignments
@count If non-null, set to number of tests performed
Returns the number of failed tests; thus, non-zero indicates failure. */
static int test(int (*func)(int off_dst, int off_src, size_t size), int *count)
{
/* Number of failed tests */
int failed = 0;
/* Number of tests */
int tests = 0;
/* For each source and destination alignment... */
for(int dst_al = 0; dst_al < 4; dst_al++)
for(int src_al = 0; src_al < 4; src_al++)
/* For each "alignment" of operation size... */
for(int len_al = 0; len_al < 4; len_al++)
{
/* Try a small size first */
failed += !!func(96 + dst_al, 96 + src_al, 12 + len_al);
/* Then a medium region without overlapping */
failed += !!func(4 + dst_al, 128 + src_al, 92 + len_al);
/* A large region with left-right overlapping */
failed += !!func(64 + dst_al, 96 + src_al, 128 + len_al);
/* A large region with right-left overlapping */
failed += !!func(96 + dst_al, 64 + src_al, 128 + len_al);
tests += 4;
}
if(count) *count = tests;
return failed;
}
//---
// Main function
//---
/* memfunctest() - check the bejavior of the core memory functions
Returns non-zero if any test fails. */
int memfunctest(void)
{
int count = 0, failed = 0, count_one, failed_one;
fill(src);
failed_one = test(test_memcpy, &count_one);
failed += failed_one;
count += count_one;
failed_one = test(test_memset, &count_one);
failed += failed_one;
count += count_one;
failed_one = test(test_memmove, &count_one);
failed += failed_one;
count += count_one;
char str[21];
sprintf(str, "Score: %d/%d.", count - failed, count);
Print(str);
return (failed != 0);
}

17
src/memfunctest.h Normal file
View File

@ -0,0 +1,17 @@
//---
// memfunctest - Check the behaviour of the core memory functions
//
// This small program checks that memcpy(), memset() and memmove() work
// properly in all source/destination alignment, size, overlap scenarios.
// It also checks both small and large areas to trigger usual optimizations.
//---
#ifndef __MEMFUNCTEST_H__
#define __MEMFUNCTEST_H__
/* memfunctest() - check the bejavior of the core memory functions
Displays the test result on the screen.
Returns non-zero if any test fails. */
int memfunctest(void);
#endif /* __MEMFUNCTEST_H__ */