196 lines
6.1 KiB
C
196 lines
6.1 KiB
C
// memcpy / memmove / memset against a byte-exact model: every length
|
|
// class (0, 1, short, both sides of the MVN threshold, long, over 64 KB),
|
|
// odd and even source and destination addresses, buffers that straddle a
|
|
// bank boundary (source, destination, both), overlapping memmove in both
|
|
// directions (short and long, across a bank edge), memset of each class
|
|
// and of a value above 255, the returned pointer, and guard bytes on both
|
|
// sides; first (memBlockRegs.s) the caller's DBR and D across every path.
|
|
// Mailbox: 0x025000 = mismatches, 0x025002 = first failing case (0xFFFF:
|
|
// none), 0x025004 = 0xC0DE done, 0x025006 = cases run, 0x025008 = 0x0FFF
|
|
// when DBR and D survived all 12 register probes; the first failure's
|
|
// dst / src (or c) / n | op << 28 at 0x025010 / 0x025014 / 0x025018.
|
|
#include "memPattern.h"
|
|
|
|
#define MB_BAD (*(volatile u16 *)0x025000UL)
|
|
#define MB_FIRST (*(volatile u16 *)0x025002UL)
|
|
#define MB_DONE (*(volatile u16 *)0x025004UL)
|
|
#define MB_CASES (*(volatile u16 *)0x025006UL)
|
|
#define MB_DST (*(volatile u32 *)0x025010UL)
|
|
#define MB_SRC (*(volatile u32 *)0x025014UL)
|
|
#define MB_N (*(volatile u32 *)0x025018UL)
|
|
|
|
#define MB_DONE_MARK 0xC0DEu
|
|
#define MB_NO_FAIL 0xFFFFu
|
|
#define GUARD 8u
|
|
#define SEED_SRC 0xC3u
|
|
#define SEED_DST 0x5Au
|
|
#define SET_BYTE 0xA5
|
|
#define SET_BIG 0x3C
|
|
#define SET_HIGH 0x100
|
|
#define BIG_LEN 70000UL
|
|
#define N_LENS 27u
|
|
#define N_SHIFTS 10u
|
|
#define N_ALIGNS 2u
|
|
#define OP_COPY 0x10000000UL
|
|
#define OP_MOVE 0x20000000UL
|
|
#define OP_SET 0x30000000UL
|
|
|
|
// Plain buffers in bank 2; bank edges at 03/04, 04/05, 05/06, 06/07 and
|
|
// 07/08 for the straddling ones.
|
|
#define PLAIN_DST 0x026000UL
|
|
#define PLAIN_SRC 0x027000UL
|
|
#define PLAIN_MOVE 0x026200UL
|
|
#define EDGE_SRC 0x040000UL
|
|
#define EDGE_DST 0x050000UL
|
|
#define EDGE_MOVE 0x060000UL
|
|
#define EDGE_SET 0x070000UL
|
|
#define BIG_SRC 0x058000UL
|
|
#define BIG_DST 0x074000UL
|
|
#define BIG_UP 0x058123UL
|
|
#define BIG_DOWN 0x057F00UL
|
|
#define BIG_SET 0x09FFFFUL
|
|
|
|
static void begin(u32 dst, u32 src, u32 n);
|
|
static void caseCopy(u32 dst, u32 src, u32 n);
|
|
static void caseMove(u32 dst, u32 src, u32 n);
|
|
static void caseSet(u32 dst, int c, u32 n);
|
|
static void fail(void);
|
|
static int guarded(u32 a, u32 n, u8 seed);
|
|
static int holdsByte(u32 a, u32 n, u8 c);
|
|
u16 memBlockRegs(void);
|
|
|
|
static const u16 kLens[N_LENS] = {
|
|
0, 1, 2, 3, 4, 5, 7, 8, 15, 16, 17, 22, 23, 24, 25, 26, 31, 32, 33, 34,
|
|
35, 64, 100, 255, 256, 257, 1000
|
|
};
|
|
static const short kShifts[N_SHIFTS] = { -100, -7, -3, -2, -1, 1, 2, 3, 7, 100 };
|
|
|
|
static u16 gBad;
|
|
static u16 gCase;
|
|
static u32 gDst;
|
|
static u32 gSrc;
|
|
static u32 gN;
|
|
|
|
|
|
static void begin(u32 dst, u32 src, u32 n) {
|
|
gDst = dst;
|
|
gSrc = src;
|
|
gN = n;
|
|
gCase++;
|
|
MB_CASES = gCase;
|
|
}
|
|
|
|
|
|
static void caseCopy(u32 dst, u32 src, u32 n) {
|
|
begin(dst, src, n | OP_COPY);
|
|
fill(dst - GUARD, n + 2u * GUARD, SEED_DST);
|
|
fill(src, n, SEED_SRC);
|
|
if (memcpy((void *)dst, (const void *)src, n) != (void *)dst ||
|
|
!holds(dst, src, n, SEED_SRC) || !guarded(dst, n, SEED_DST)) {
|
|
fail();
|
|
}
|
|
}
|
|
|
|
|
|
// One region holds both blocks: after the move [dst, dst + n) holds what
|
|
// [src, src + n) held and the rest of the window is untouched.
|
|
static void caseMove(u32 dst, u32 src, u32 n) {
|
|
u32 lo = (dst < src) ? dst : src;
|
|
u32 hi = ((dst < src) ? src : dst) + n;
|
|
begin(dst, src, n | OP_MOVE);
|
|
fill(lo - GUARD, hi - lo + 2u * GUARD, SEED_SRC);
|
|
if (memmove((void *)dst, (const void *)src, n) != (void *)dst ||
|
|
!holds(dst, src, n, SEED_SRC) ||
|
|
!holds(lo - GUARD, lo - GUARD, dst - (lo - GUARD), SEED_SRC) ||
|
|
!holds(dst + n, dst + n, hi + GUARD - (dst + n), SEED_SRC)) {
|
|
fail();
|
|
}
|
|
}
|
|
|
|
|
|
static void caseSet(u32 dst, int c, u32 n) {
|
|
begin(dst, (u32)c, n | OP_SET);
|
|
fill(dst - GUARD, n + 2u * GUARD, SEED_DST);
|
|
if (memset((void *)dst, c, n) != (void *)dst ||
|
|
!holdsByte(dst, n, (u8)c) || !guarded(dst, n, SEED_DST)) {
|
|
fail();
|
|
}
|
|
}
|
|
|
|
|
|
static void fail(void) {
|
|
if (gBad == 0u) {
|
|
MB_FIRST = gCase;
|
|
MB_DST = gDst;
|
|
MB_SRC = gSrc;
|
|
MB_N = gN;
|
|
}
|
|
gBad++;
|
|
MB_BAD = gBad;
|
|
}
|
|
|
|
|
|
// The GUARD bytes on each side of [a, a + n) still hold their own pattern.
|
|
static int guarded(u32 a, u32 n, u8 seed) {
|
|
return holds(a - GUARD, a - GUARD, GUARD, seed) && holds(a + n, a + n, GUARD, seed);
|
|
}
|
|
|
|
|
|
static int holdsByte(u32 a, u32 n, u8 c) {
|
|
const u8 *p = (const u8 *)a;
|
|
while (n != 0u) {
|
|
u16 run = (n > 0x8000UL) ? 0x8000u : (u16)n;
|
|
u16 i;
|
|
for (i = 0; i < run; i++) {
|
|
if (p[i] != c) {
|
|
return 0;
|
|
}
|
|
}
|
|
p += run;
|
|
n -= run;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
int main(void) {
|
|
u16 li;
|
|
u16 d;
|
|
u16 s;
|
|
u16 k;
|
|
// DBR and D survive every path (memBlockRegs.s writes 0x025008 itself).
|
|
(void)memBlockRegs();
|
|
for (li = 0; li < N_LENS; li++) {
|
|
u32 n = kLens[li];
|
|
u32 half = n / 2u;
|
|
for (d = 0; d < N_ALIGNS; d++) {
|
|
for (s = 0; s < N_ALIGNS; s++) {
|
|
// Plain, source across 03/04, destination across 04/05,
|
|
// both across (at different points of the run).
|
|
caseCopy(PLAIN_DST + d, PLAIN_SRC + s, n);
|
|
caseCopy(PLAIN_DST + d, EDGE_SRC - half + s, n);
|
|
caseCopy(EDGE_DST - half + d, PLAIN_SRC + s, n);
|
|
caseCopy(EDGE_DST - half + d, EDGE_SRC - n / 3u + s, n);
|
|
}
|
|
}
|
|
for (k = 0; k < N_SHIFTS; k++) {
|
|
caseMove(PLAIN_MOVE + (long)kShifts[k], PLAIN_MOVE, n);
|
|
caseMove(EDGE_MOVE - half + (long)kShifts[k], EDGE_MOVE - half, n);
|
|
}
|
|
caseSet(PLAIN_DST + (li & 1u), SET_BYTE, n);
|
|
caseSet(EDGE_SET - half, SET_HIGH + li, n);
|
|
}
|
|
// Over 64 KB: several MVN / MVP runs, every bank byte stepping.
|
|
caseCopy(BIG_DST, BIG_SRC, BIG_LEN);
|
|
caseMove(BIG_UP, BIG_SRC, BIG_LEN);
|
|
caseMove(BIG_DOWN, BIG_SRC, BIG_LEN);
|
|
caseSet(BIG_SET, SET_BIG, BIG_LEN);
|
|
MB_BAD = gBad;
|
|
if (gBad == 0u) {
|
|
MB_FIRST = MB_NO_FAIL;
|
|
}
|
|
MB_DONE = MB_DONE_MARK;
|
|
for (;;) {
|
|
}
|
|
return 0;
|
|
}
|