flashwear.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // Wear-leveling wrapper around the internal Flash driver.
  2. class FlashWear {
  3. static constexpr bool DEBUG = false;
  4. static constexpr int SECLEN = 128;
  5. static constexpr int NUM_MODS = 500;
  6. static constexpr int SEC_PER_SEG = 1024;
  7. static constexpr int SEGSUSED = 6; // plus one spare
  8. typedef struct {
  9. uint16_t map [NUM_MODS];
  10. uint8_t flags [NUM_MODS];
  11. uint8_t phys [SEGSUSED];
  12. uint8_t spare [36-SEGSUSED];
  13. uint8_t sectors [NUM_MODS][SECLEN];
  14. } ModPage;
  15. typedef uint8_t Segment [SEC_PER_SEG][SECLEN];
  16. static ModPage const& mods; // used to collect all changes
  17. static Segment const* segs; // actual data storage segments
  18. static uint16_t fill; // next unused entry in map
  19. static void reFlashChanges () {
  20. if (DEBUG)
  21. printf("reFlashChanges\n");
  22. uint16_t counts [SEGSUSED];
  23. memset(counts, 0, sizeof counts);
  24. // count how many changes there are in each segment, after merging
  25. for (int seg = 0; seg < SEGSUSED; ++seg) {
  26. // keep track of all sectors, only count each sector once
  27. uint8_t useBits [SEC_PER_SEG/8];
  28. memset(useBits, 0, sizeof useBits);
  29. for (int i = 0; i < fill; ++i)
  30. if (mods.map[i] / SEC_PER_SEG == seg) {
  31. int n = mods.map[i] % SEC_PER_SEG;
  32. if ((useBits[n/8] & (1<<(n%8))) == 0) {
  33. useBits[n/8] |= 1<<(n%8);
  34. ++counts[seg];
  35. }
  36. }
  37. }
  38. // start re-flashing segments, until only a few changes remain
  39. uint8_t newPhys [SEGSUSED];
  40. memcpy(newPhys, mods.phys, sizeof newPhys);
  41. for (;;) {
  42. if (DEBUG) {
  43. printf("counts:");
  44. for (int i = 0; i < SEGSUSED; ++i)
  45. printf(" %d", counts[i]);
  46. printf("\n");
  47. printf("newPhys:");
  48. for (int i = 0; i < SEGSUSED; ++i)
  49. printf(" %d", newPhys[i]);
  50. printf("\n");
  51. }
  52. uint32_t remain = 0, nextSeg = 0;
  53. for (int i = 0; i < SEGSUSED; ++i) {
  54. remain += counts[i];
  55. if (counts[i] > counts[nextSeg])
  56. nextSeg = i;
  57. }
  58. if (DEBUG)
  59. printf("remain %d nextSeg %d\n", remain, nextSeg);
  60. //if (remain <= 30) // TODO needs more logic to migrate remaining
  61. if (remain == 0) {
  62. // changes have been merged back, now clean up the mods page
  63. Flash::erasePage(&mods);
  64. for (int i = 0; i < SEGSUSED; ++i)
  65. Flash::write8(mods.phys + i, newPhys[i]);
  66. fill = remain; // TODO will always be zero for now
  67. return;
  68. }
  69. // dumb way to find *the* segment which is currently not being used
  70. // careful, maps.phys/newPhys/freePhys are PHYSICAL segments (+1) !
  71. int freePhys = 0;
  72. for (int i = 1; i <= SEGSUSED+1; ++i)
  73. if (memchr(newPhys, i, SEGSUSED) == 0)
  74. freePhys = i;
  75. // prepare to update the unused segment, leaving behind the old one
  76. if (DEBUG)
  77. printf("reflash seg %d: phys %d to %d\n",
  78. nextSeg, newPhys[nextSeg], freePhys);
  79. // erase the segment, then copy the latest sector versions into it
  80. Flash::erasePage(segs[freePhys]);
  81. for (int i = 0; i < SEC_PER_SEG; ++i) {
  82. uint8_t buf [SECLEN];
  83. readSector(nextSeg * SEC_PER_SEG + i, buf);
  84. if (DEBUG)
  85. printf("rewrite %d seg %d\n", i, freePhys);
  86. Flash::write32buf(segs[freePhys][i], (uint32_t*) buf, SECLEN/4);
  87. }
  88. newPhys[nextSeg] = freePhys;
  89. counts[nextSeg] = 0;
  90. }
  91. }
  92. public:
  93. static bool valid () {
  94. for (int i = 0; i < SEGSUSED; ++i)
  95. if (mods.phys[0] <= 0 || mods.phys[0] > SEGSUSED+1)
  96. return false;
  97. return true;
  98. }
  99. static int init (bool erase =false) {
  100. if (DEBUG)
  101. printf("FlashWear %d, ModPage %d, Segment %d\n",
  102. sizeof (FlashWear), sizeof (ModPage), sizeof (Segment));
  103. if (erase || !valid()) {
  104. printf("initialising internal flash\n");
  105. Flash::erasePage(&mods);
  106. for (int i = 0; i < SEGSUSED; ++i)
  107. Flash::write8(mods.phys + i, i+2);
  108. }
  109. for (fill = NUM_MODS; mods.map[fill-1] == 0xFFFF; --fill)
  110. if (fill == 0)
  111. break;
  112. if (DEBUG) {
  113. printf("fill %d, phys:", fill);
  114. for (int i = 0; i < SEGSUSED; ++i)
  115. printf(" %d", mods.phys[i]);
  116. printf("\n");
  117. }
  118. uint32_t memSizeKb = MMIO16(0x1FFF7A22); // TODO F407-specific?
  119. return (memSizeKb/256-1) * (256*8); // 512 = 1 disk, 1024 = 3 disks
  120. }
  121. static void readSector (int pos, void* buf) {
  122. for (int i = fill; --i >= 0; )
  123. if (mods.map[i] == pos) {
  124. if (DEBUG)
  125. printf("readSector %d mod %d\n", pos, i);
  126. memcpy(buf, mods.sectors[i], SECLEN);
  127. return; // return modified sector
  128. }
  129. // no changed version found, return the original sector
  130. int segPhys = mods.phys[pos/SEC_PER_SEG];
  131. if (DEBUG)
  132. printf("readSector %d seg %d @ %d\n",
  133. pos, segPhys, pos % SEC_PER_SEG);
  134. memcpy(buf, segs[segPhys][pos%SEC_PER_SEG], SECLEN);
  135. }
  136. static void writeSector (int pos, void const* buf) {
  137. if (fill >= NUM_MODS)
  138. reFlashChanges();
  139. int n = fill++;
  140. if (DEBUG)
  141. printf("writeSector %d mod %d\n", pos, n);
  142. Flash::write16(mods.map + n, pos);
  143. Flash::write32buf(mods.sectors[n], (uint32_t const*) buf, SECLEN/4);
  144. }
  145. };
  146. FlashWear::ModPage const& FlashWear::mods =
  147. *(FlashWear::ModPage const*) 0x00010000; // @ 64K
  148. FlashWear::Segment const* FlashWear::segs =
  149. (FlashWear::Segment const*) 0x00020000; // @ 128K
  150. uint16_t FlashWear::fill = 0;