/* ChibiOS/RT - Copyright (C) 2013-2014 Uladzimir Pylinsky aka barthess Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include #include #include #include #include "memtest.h" static unsigned int prng_seed = 42; /* * */ template class Generator { public: Generator(void) : pattern(0) {;} virtual T get(void) = 0; virtual testtype get_type(void) = 0; virtual void init(T seed) { pattern = seed; } protected: T pattern; }; /* * */ template class GeneratorWalkingOne : public Generator { T get(void) { T ret = this->pattern; this->pattern <<= 1; if (0 == this->pattern) this->pattern = 1; return ret; } testtype get_type(void) { return MEMTEST_WALKING_ONE; } }; /* * */ template class GeneratorWalkingZero : public Generator { T get(void) { T ret = ~this->pattern; this->pattern <<= 1; if (0 == this->pattern) this->pattern = 1; return ret; } testtype get_type(void) { return MEMTEST_WALKING_ZERO; } }; /* * */ template class GeneratorOwnAddress : public Generator { T get(void) { T ret = this->pattern; this->pattern++; return ret; } testtype get_type(void) { return MEMTEST_OWN_ADDRESS; } }; /* * */ template class GeneratorMovingInv : public Generator { T get(void) { T ret = this->pattern; this->pattern = ~this->pattern; return ret; } testtype get_type(void) { if ((this->pattern == 0) || ((this->pattern & 0xFF) == 0xFF)) return MEMTEST_MOVING_INVERSION_ZERO; else return MEMTEST_MOVING_INVERSION_55AA; } }; /* * */ template class GeneratorMovingInvRand : public Generator { public: GeneratorMovingInvRand(void) : step(0), prev(0){;} void init(T seed) { srand(seed); step = 0; prev = 0; } T get(void) { T ret; if ((step & 1) == 0) { ret = 0; ret |= rand(); // for uint64_t we need to call rand() twice if (8 == sizeof(T)) { // multiplication used instead of 32 bit shift for warning avoidance ret *= 0x100000000; ret |= rand(); } prev = ret; } else { ret = ~prev; } step++; return ret; } testtype get_type(void) { return MEMTEST_MOVING_INVERSION_RAND; } private: size_t step; T prev; }; /* * */ template static void memtest_sequential(memtest_t *testp, Generator &generator, T seed) { const size_t steps = testp->size / sizeof(T); size_t i; T *mem = static_cast(testp->start); T got; T expect; /* fill ram */ generator.init(seed); for (i=0; ierrcb)) { testp->errcb(testp, generator.get_type(), i, sizeof(T), got, expect); return; } } } template static void walking_one(memtest_t *testp) { GeneratorWalkingOne generator; memtest_sequential(testp, generator, 1); } template static void walking_zero(memtest_t *testp) { GeneratorWalkingZero generator; memtest_sequential(testp, generator, 1); } template static void own_address(memtest_t *testp) { GeneratorOwnAddress generator; memtest_sequential(testp, generator, 0); } template static void moving_inversion_zero(memtest_t *testp) { GeneratorMovingInv generator; T seed; seed = 0; memtest_sequential(testp, generator, seed); seed = ~seed; memtest_sequential(testp, generator, seed); } template static void moving_inversion_55aa(memtest_t *testp) { GeneratorMovingInv generator; T seed; memset(&seed, 0x55, sizeof(seed)); memtest_sequential(testp, generator, seed); seed = ~seed; memtest_sequential(testp, generator, seed); } template static void moving_inversion_rand(memtest_t *testp) { GeneratorMovingInvRand generator; T mask = -1; prng_seed++; memtest_sequential(testp, generator, prng_seed & mask); } /* * */ static void memtest_wrapper(memtest_t *testp, void (*p_u8) (memtest_t *testp), void (*p_u16)(memtest_t *testp), void (*p_u32)(memtest_t *testp), void (*p_u64)(memtest_t *testp)) { if (testp->width_mask & MEMTEST_WIDTH_8) p_u8(testp); if (testp->width_mask & MEMTEST_WIDTH_16) p_u16(testp); if (testp->width_mask & MEMTEST_WIDTH_32) p_u32(testp); if (testp->width_mask & MEMTEST_WIDTH_64) p_u64(testp); } /* * */ void memtest_run(memtest_t *testp, uint32_t testmask) { if (testmask & MEMTEST_WALKING_ONE) { memtest_wrapper(testp, walking_one, walking_one, walking_one, walking_one); } if (testmask & MEMTEST_WALKING_ZERO) { memtest_wrapper(testp, walking_zero, walking_zero, walking_zero, walking_zero); } if (testmask & MEMTEST_OWN_ADDRESS) { memtest_wrapper(testp, own_address, own_address, own_address, own_address); } if (testmask & MEMTEST_MOVING_INVERSION_ZERO) { memtest_wrapper(testp, moving_inversion_zero, moving_inversion_zero, moving_inversion_zero, moving_inversion_zero); } if (testmask & MEMTEST_MOVING_INVERSION_55AA) { memtest_wrapper(testp, moving_inversion_55aa, moving_inversion_55aa, moving_inversion_55aa, moving_inversion_55aa); } if (testmask & MEMTEST_MOVING_INVERSION_RAND) { memtest_wrapper(testp, moving_inversion_rand, moving_inversion_rand, moving_inversion_rand, moving_inversion_rand); } }