Procházet zdrojové kódy

floppy: Avoid 16-bit overflow when reading No Flux Areas.

Keir Fraser před 5 roky
rodič
revize
b6af06bb02
2 změnil soubory, kde provedl 32 přidání a 15 odebrání
  1. 2 2
      scripts/gw.py
  2. 30 13
      src/floppy.c

+ 2 - 2
scripts/gw.py

@@ -233,13 +233,13 @@ def read(args):
     for x in flux:
       y = x * factor + rem
       val = int(round(y))
+      if (val & 65535) == 0:
+        val += 1
       rem = y - val
       while val >= 65536:
         trk_dat.append(0)
         trk_dat.append(0)
         val -= 65536
-      if val == 0:
-        val = 1
       trk_dat.append(val>>8)
       trk_dat.append(val&255)
   print()

+ 30 - 13
src/floppy.c

@@ -354,7 +354,8 @@ static struct {
 static void rdata_encode_flux(void)
 {
     const uint16_t buf_mask = ARRAY_SIZE(dma.buf) - 1;
-    uint16_t cons, prod, prev = dma.prev_sample, curr, next;
+    uint16_t cons = dma.cons, prod, prev = dma.prev_sample, curr, next;
+    uint32_t ticks = rw.ticks_since_flux;
     unsigned int nr_samples;
 
     ASSERT(rw.rev < rw.nr_revs);
@@ -364,12 +365,12 @@ static void rdata_encode_flux(void)
 
     /* Find out where the DMA engine's producer index has got to. */
     prod = ARRAY_SIZE(dma.buf) - dma_rdata.cndtr;
-    nr_samples = (prod - dma.cons) & buf_mask;
+    nr_samples = (prod - cons) & buf_mask;
 
     if (rw.rev != index.count) {
         /* We have just passed the index mark: Record information about 
          * the just-completed revolution. */
-        unsigned int final_samples = (index.read_prod - dma.cons) & buf_mask;
+        unsigned int final_samples = (index.read_prod - cons) & buf_mask;
         if (final_samples > nr_samples) {
             /* Only way this can happen is if the producer has overflowed 
              * past the consumer since the Index IRQ. We will report it 
@@ -390,36 +391,52 @@ static void rdata_encode_flux(void)
     rw.nr_samples += nr_samples;
 
     /* Process the flux timings into the raw bitcell buffer. */
-    for (cons = dma.cons; cons != prod; cons = (cons+1) & buf_mask) {
+    for (; cons != prod; cons = (cons+1) & buf_mask) {
         next = dma.buf[cons];
         curr = next - prev;
         prev = next;
 
-        if (curr == 0) {
+        ticks += curr;
+
+        if (ticks == 0) {
             /* 0: Skip. */
-        } else if (curr < 250) {
+        } else if (ticks < 250) {
             /* 1-249: One byte. */
-            u_buf[U_MASK(u_prod++)] = curr;
+            u_buf[U_MASK(u_prod++)] = ticks;
         } else {
-            unsigned int high = curr / 250;
+            unsigned int high = ticks / 250;
             if (high <= 5) {
                 /* 250-1499: Two bytes. */
                 u_buf[U_MASK(u_prod++)] = 249 + high;
-                u_buf[U_MASK(u_prod++)] = 1 + (curr % 250);
+                u_buf[U_MASK(u_prod++)] = 1 + (ticks % 250);
             } else {
                 /* 1500-(2^28-1): Five bytes */
                 u_buf[U_MASK(u_prod++)] = 0xff;
-                u_buf[U_MASK(u_prod++)] = 1 | (curr << 1);
-                u_buf[U_MASK(u_prod++)] = 1 | (curr >> 6);
-                u_buf[U_MASK(u_prod++)] = 1 | (curr >> 13);
-                u_buf[U_MASK(u_prod++)] = 1 | (curr >> 20);
+                u_buf[U_MASK(u_prod++)] = 1 | (ticks << 1);
+                u_buf[U_MASK(u_prod++)] = 1 | (ticks >> 6);
+                u_buf[U_MASK(u_prod++)] = 1 | (ticks >> 13);
+                u_buf[U_MASK(u_prod++)] = 1 | (ticks >> 20);
             }
         }
+
+        ticks = 0;
+    }
+
+    /* If it has been a long time since the last flux timing, transfer some of
+     * the accumulated time from the 16-bit timestamp into the 32-bit
+     * accumulator. This avoids 16-bit overflow and because, we take care to
+     * keep the 16-bit timestamp at least 200us behind, we cannot race the next
+     * flux timestamp. */
+    curr = tim_rdata->cnt - prev;
+    if (unlikely(curr > sysclk_us(400))) {
+        prev += sysclk_us(200);
+        ticks += sysclk_us(200);
     }
 
     /* Save our progress for next time. */
     dma.cons = cons;
     dma.prev_sample = prev;
+    rw.ticks_since_flux = ticks;
 }
 
 static void floppy_read_prep(unsigned int revs)