spi_flash_emulation.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. #ifndef spi_flash_emulation_h
  14. #define spi_flash_emulation_h
  15. #include <vector>
  16. #include <cassert>
  17. #include <algorithm>
  18. #include <random>
  19. #include "esp_spi_flash.h"
  20. #include "catch.hpp"
  21. using std::copy;
  22. using std::begin;
  23. using std::end;
  24. using std::fill_n;
  25. class SpiFlashEmulator;
  26. void spi_flash_emulator_set(SpiFlashEmulator*);
  27. class SpiFlashEmulator
  28. {
  29. public:
  30. SpiFlashEmulator(size_t sectorCount) : mUpperSectorBound(sectorCount)
  31. {
  32. mData.resize(sectorCount * SPI_FLASH_SEC_SIZE / 4, 0xffffffff);
  33. mEraseCnt.resize(sectorCount);
  34. spi_flash_emulator_set(this);
  35. }
  36. SpiFlashEmulator(const char *filename)
  37. {
  38. load(filename);
  39. // Atleast one page should be free, hence we create mData of size of 2 sectors.
  40. mData.resize(mData.size() + SPI_FLASH_SEC_SIZE / 4, 0xffffffff);
  41. mUpperSectorBound = mData.size() * 4 / SPI_FLASH_SEC_SIZE;
  42. spi_flash_emulator_set(this);
  43. }
  44. ~SpiFlashEmulator()
  45. {
  46. spi_flash_emulator_set(nullptr);
  47. }
  48. bool read(uint32_t* dest, size_t srcAddr, size_t size) const
  49. {
  50. if (srcAddr % 4 != 0 ||
  51. size % 4 != 0 ||
  52. srcAddr + size > mData.size() * 4) {
  53. return false;
  54. }
  55. copy(begin(mData) + srcAddr / 4, begin(mData) + (srcAddr + size) / 4, dest);
  56. ++mReadOps;
  57. mReadBytes += size;
  58. mTotalTime += getReadOpTime(static_cast<uint32_t>(size));
  59. return true;
  60. }
  61. bool write(size_t dstAddr, const uint32_t* src, size_t size)
  62. {
  63. uint32_t sectorNumber = dstAddr/SPI_FLASH_SEC_SIZE;
  64. if (sectorNumber < mLowerSectorBound || sectorNumber >= mUpperSectorBound) {
  65. WARN("invalid flash operation detected: erase sector=" << sectorNumber);
  66. return false;
  67. }
  68. if (dstAddr % 4 != 0 ||
  69. size % 4 != 0 ||
  70. dstAddr + size > mData.size() * 4) {
  71. return false;
  72. }
  73. for (size_t i = 0; i < size / 4; ++i) {
  74. if (mFailCountdown != SIZE_MAX && mFailCountdown-- == 0) {
  75. return false;
  76. }
  77. uint32_t sv = src[i];
  78. size_t pos = dstAddr / 4 + i;
  79. uint32_t& dv = mData[pos];
  80. if (((~dv) & sv) != 0) { // are we trying to set some 0 bits to 1?
  81. WARN("invalid flash operation detected: dst=" << dstAddr << " size=" << size << " i=" << i);
  82. return false;
  83. }
  84. dv = sv;
  85. }
  86. ++mWriteOps;
  87. mWriteBytes += size;
  88. mTotalTime += getWriteOpTime(static_cast<uint32_t>(size));
  89. return true;
  90. }
  91. bool erase(size_t sectorNumber)
  92. {
  93. size_t offset = sectorNumber * SPI_FLASH_SEC_SIZE / 4;
  94. if (offset > mData.size()) {
  95. return false;
  96. }
  97. if (sectorNumber < mLowerSectorBound || sectorNumber >= mUpperSectorBound) {
  98. WARN("invalid flash operation detected: erase sector=" << sectorNumber);
  99. return false;
  100. }
  101. if (mFailCountdown != SIZE_MAX && mFailCountdown-- == 0) {
  102. return false;
  103. }
  104. std::fill_n(begin(mData) + offset, SPI_FLASH_SEC_SIZE / 4, 0xffffffff);
  105. ++mEraseOps;
  106. mEraseCnt[sectorNumber]++;
  107. mTotalTime += getEraseOpTime();
  108. return true;
  109. }
  110. void randomize(uint32_t seed)
  111. {
  112. std::random_device rd;
  113. std::mt19937 gen(rd());
  114. gen.seed(seed);
  115. std::generate_n(mData.data(), mData.size(), gen);
  116. }
  117. size_t size() const
  118. {
  119. return mData.size() * 4;
  120. }
  121. const uint32_t* words() const
  122. {
  123. return mData.data();
  124. }
  125. const uint8_t* bytes() const
  126. {
  127. return reinterpret_cast<const uint8_t*>(mData.data());
  128. }
  129. void load(const char* filename)
  130. {
  131. FILE* f = fopen(filename, "rb");
  132. fseek(f, 0, SEEK_END);
  133. off_t size = ftell(f);
  134. assert(size % SPI_FLASH_SEC_SIZE == 0);
  135. mData.resize(size / sizeof(uint32_t));
  136. fseek(f, 0, SEEK_SET);
  137. auto s = fread(mData.data(), SPI_FLASH_SEC_SIZE, size / SPI_FLASH_SEC_SIZE, f);
  138. assert(s == static_cast<size_t>(size / SPI_FLASH_SEC_SIZE));
  139. fclose(f);
  140. }
  141. void save(const char* filename)
  142. {
  143. FILE* f = fopen(filename, "wb");
  144. auto n_sectors = mData.size() * sizeof(uint32_t) / SPI_FLASH_SEC_SIZE;
  145. auto s = fwrite(mData.data(), SPI_FLASH_SEC_SIZE, n_sectors, f);
  146. assert(s == n_sectors);
  147. fclose(f);
  148. }
  149. void clearStats()
  150. {
  151. mReadBytes = 0;
  152. mWriteBytes = 0;
  153. mEraseOps = 0;
  154. mReadOps = 0;
  155. mWriteOps = 0;
  156. mTotalTime = 0;
  157. }
  158. size_t getReadOps() const
  159. {
  160. return mReadOps;
  161. }
  162. size_t getWriteOps() const
  163. {
  164. return mWriteOps;
  165. }
  166. size_t getEraseOps() const
  167. {
  168. return mEraseOps;
  169. }
  170. size_t getReadBytes() const
  171. {
  172. return mReadBytes;
  173. }
  174. size_t getWriteBytes() const
  175. {
  176. return mWriteBytes;
  177. }
  178. size_t getTotalTime() const
  179. {
  180. return mTotalTime;
  181. }
  182. void setBounds(uint32_t lowerSector, uint32_t upperSector) {
  183. mLowerSectorBound = lowerSector;
  184. mUpperSectorBound = upperSector;
  185. }
  186. void failAfter(uint32_t count) {
  187. mFailCountdown = count;
  188. }
  189. size_t getSectorEraseCount(uint32_t sector) const {
  190. return mEraseCnt[sector];
  191. }
  192. protected:
  193. static size_t getReadOpTime(uint32_t bytes);
  194. static size_t getWriteOpTime(uint32_t bytes);
  195. static size_t getEraseOpTime();
  196. std::vector<uint32_t> mData;
  197. std::vector<uint32_t> mEraseCnt;
  198. mutable size_t mReadOps = 0;
  199. mutable size_t mWriteOps = 0;
  200. mutable size_t mReadBytes = 0;
  201. mutable size_t mWriteBytes = 0;
  202. mutable size_t mEraseOps = 0;
  203. mutable size_t mTotalTime = 0;
  204. size_t mLowerSectorBound = 0;
  205. size_t mUpperSectorBound = 0;
  206. size_t mFailCountdown = SIZE_MAX;
  207. };
  208. #endif /* spi_flash_emulation_h */