]> git.the-white-hart.net Git - vhdl/commitdiff
Add autoerase to digdude
authorRyan <>
Fri, 26 Sep 2025 23:42:39 +0000 (18:42 -0500)
committerRyan <>
Fri, 26 Sep 2025 23:42:39 +0000 (18:42 -0500)
projects/nexys2_host_controller/host/digdude.c

index 135d73bd4d546cd3a3293b42f217798915e47e51..6a979d4f5f48ff41ebfdfb5fad92f2af0fbe21f8 100644 (file)
@@ -26,6 +26,112 @@ enum exitspec { X_RESET, X_NORESET };
 // -----------------------------------------------------------------------------
 
 
+typedef struct
+{
+       uint32_t block_size;
+       uint32_t block_count;
+       uint8_t  block_is_erased[0x10000];
+} erase_region_t;
+
+
+typedef struct
+{
+       uint8_t        region_count;
+       erase_region_t regions[256];
+} erase_info_t;
+
+
+static erase_info_t erase_info;
+
+
+bool get_erase_info(HIF hif)
+{
+       assert(hif != hifInvalid);
+
+       uint8_t cfi_buf[0x100];
+
+       // Read and verify CFI query information
+       EC_FALSE(flash_cfi(hif, 0, cfi_buf, sizeof(cfi_buf)));
+       EC_FALSE(cfi_buf[0x10] == 'Q');
+       EC_FALSE(cfi_buf[0x11] == 'R');
+       EC_FALSE(cfi_buf[0x12] == 'Y');
+
+       // Flash chips can contain multiple "erase regions," each of which
+       // contains some number of equal-sized eraseable blocks
+
+       // Read the number of regions from the CFI query and loop for each
+       erase_info.region_count = cfi_buf[0x2c];
+
+       for (size_t i = 0; i < erase_info.region_count; i++)
+       {
+               size_t block_info_idx = 0x2d + (4 * i);
+               assert(block_info_idx < 0x100);  // Just in case
+
+               // Read the geometry of this region's blocks from the CFI query
+               uint32_t block_count = ((cfi_buf[block_info_idx + 1] << 8) |
+                                        cfi_buf[block_info_idx + 0]) + 1;
+               uint32_t block_size  = ((cfi_buf[block_info_idx + 3] << 8) |
+                                        cfi_buf[block_info_idx + 2]) * 256;
+               if (block_size == 0) block_size = 128;
+
+               erase_info.regions[i].block_size  = block_size;
+               erase_info.regions[i].block_count = block_count;
+       }
+
+       return true;
+
+EC_CLEANUP_BEGIN
+       return false;
+EC_CLEANUP_END
+}
+
+
+bool ensure_erased(HIF hif, uint32_t addr, size_t data_len)
+{
+       assert(hif != hifInvalid);
+
+       uint32_t scan_addr = 0;
+
+       uint32_t region_count = erase_info.region_count;
+       for (uint32_t i = 0; i < region_count; i++)
+       {
+               uint32_t block_count = erase_info.regions[i].block_count;
+               for (uint32_t j = 0; j < block_count; j++)
+               {
+                       uint32_t block_size  = erase_info.regions[i].block_size;
+                       uint32_t block_start = scan_addr;
+                       uint32_t block_end   = scan_addr + block_size;
+
+                       uint32_t data_start  = addr;
+                       uint32_t data_end    = data_start + data_len;
+
+                       if (data_start < block_end && data_end > block_start)
+                       {
+                               if (!erase_info.regions[i].block_is_erased[j])
+                               {
+                                       printf("Erase region:%u of %u, block:%u of %u, addr:%08x size:%08x\n",
+                                              i+1, region_count,
+                                              j+1, block_count,
+                                              block_start, block_size);
+                                       EC_FALSE(flash_erase(hif, scan_addr));
+                                       erase_info.regions[i].block_is_erased[j] = 1;
+                               }
+                       }
+                       scan_addr = block_end;
+               }
+       }
+
+       return true;
+
+EC_CLEANUP_BEGIN
+       return false;
+EC_CLEANUP_END
+}
+
+
+// -----------------------------------------------------------------------------
+
+
 bool update_ram_read(HIF hif, struct iter *iter, uint32_t addr, size_t data_len)
 {
        assert(hif != hifInvalid);
@@ -178,25 +284,14 @@ bool update_flash_write(HIF hif, struct iter *iter, bool erase, bool verify)
        assert(hif != hifInvalid);
        assert(iter != NULL);
 
-       uint32_t unerased_watermark = 0;
-       uint8_t cfi_buf[0x100];
-       uint8_t num_erase_regions;
-
-       // Read and verify CFI query information
-       EC_FALSE(flash_cfi(hif, 0, cfi_buf, sizeof(cfi_buf)));
-       EC_FALSE(cfi_buf[0x10] == 'Q');
-       EC_FALSE(cfi_buf[0x11] == 'R');
-       EC_FALSE(cfi_buf[0x12] == 'Y');
-
-       // Read the number of regions from the CFI query and loop for each
-       num_erase_regions = cfi_buf[0x2c];
+       if (erase) EC_FALSE(get_erase_info(hif));
 
        while (!iter_done(iter))
        {
                EC_FALSE(iter_next(iter));
                if (erase)
                {
-                       // TODO
+                       EC_FALSE(ensure_erased(hif, iter->address, iter->data_len));
                }
                EC_FALSE(flash_write(hif, iter->address, iter->data, iter->data_len));