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