Browse Source

floppy: Allow writes to be terminated at index, and allow index to be delayed.

Keir Fraser 5 years ago
parent
commit
4c2f9213b8
3 changed files with 68 additions and 14 deletions
  1. 9 2
      inc/cdc_acm_protocol.h
  2. 1 1
      scripts/gw.py
  3. 58 11
      src/floppy.c

+ 9 - 2
inc/cdc_acm_protocol.h

@@ -21,9 +21,11 @@
 #define CMD_GET_DELAYS      4
 /* CMD_MOTOR, length=3, motor_state */
 #define CMD_MOTOR           5
-/* CMD_READ_FLUX, length=3, #revs. Returns flux readings until EOStream. */
+/* CMD_READ_FLUX, length=3, #index_pulses.
+ * Returns flux readings until EOStream. */
 #define CMD_READ_FLUX       6
-/* CMD_WRITE_FLUX, length=2. Host follows with flux readings until EOStream. */
+/* CMD_WRITE_FLUX, length=2-7. Optionally include all or part of gw_write_flux.
+ * Host follows with flux readings until EOStream. */
 #define CMD_WRITE_FLUX      7
 /* CMD_GET_FLUX_STATUS, length=2. Last read/write status returned in ACK. */
 #define CMD_GET_FLUX_STATUS 8
@@ -53,6 +55,11 @@ struct __packed gw_info {
     uint32_t sample_freq;
 };
 
+struct __packed gw_write_flux {
+    uint32_t index_delay_ticks; /* default: 0 */
+    uint8_t terminate_at_index; /* default: 0 */
+};
+
 /*
  * Local variables:
  * mode: C

+ 1 - 1
scripts/gw.py

@@ -141,7 +141,7 @@ def write_flux(flux):
   retry = 0
   while True:
     start = timer()
-    send_cmd(struct.pack("2B", CMD_WRITE_FLUX, 2))
+    send_cmd(struct.pack("<2BIB", CMD_WRITE_FLUX, 7, 0, 1))
     ser.write(x)
     ser.read(1) # Sync with Greaseweazle
     try:

+ 58 - 11
src/floppy.c

@@ -63,11 +63,21 @@ static struct {
 
 #define irq_index 23
 void IRQ_23(void) __attribute__((alias("IRQ_INDEX_changed"))); /* EXTI9_5 */
-static volatile struct index {
-    unsigned int count;
-    unsigned int rdata_cnt;
+static struct index {
+    /* Main code can reset this at will. */
+    volatile unsigned int count;
+    /* For synchronising index pulse reporting to the RDATA flux stream. */
+    volatile unsigned int rdata_cnt;
+    /* Following fields are for delayed-index writes. */
+    unsigned int delay;
+    struct timer delay_timer;
+    time_t timestamp;
 } index;
 
+#define irq_index_delay 31
+void IRQ_31(void) __attribute__((alias("IRQ_INDEX_delay")));
+static void index_delay_timer(void *unused);
+
 /* A DMA buffer for running a timer associated with a floppy-data I/O pin. */
 static struct dma_ring {
     /* Indexes into the buf[] ring buffer. */
@@ -261,7 +271,10 @@ void floppy_init(void)
     /* PB[15:0] -> EXT[15:0] */
     afio->exticr1 = afio->exticr2 = afio->exticr3 = afio->exticr4 = 0x1111;
 
-    /* Configure INDEX-changed IRQ. */
+    /* Configure INDEX-changed IRQs and timer. */
+    timer_init(&index.delay_timer, index_delay_timer, NULL);
+    IRQx_set_prio(irq_index_delay, TIMER_IRQ_PRI);
+    IRQx_enable(irq_index_delay);
     exti->rtsr = 0;
     exti->imr = exti->ftsr = m(pin_index);
     IRQx_set_prio(irq_index, INDEX_IRQ_PRI);
@@ -336,6 +349,7 @@ static struct {
     uint8_t idx, nr_idx;
     bool_t packet_ready;
     bool_t write_finished;
+    bool_t terminate_at_index;
     unsigned int packet_len;
     int ticks_since_index;
     uint32_t ticks_since_flux;
@@ -627,7 +641,7 @@ static void floppy_process_write_packet(void)
     }
 }
 
-static void floppy_write_prep(void)
+static void floppy_write_prep(struct gw_write_flux *wf)
 {
     /* Initialise DMA ring indexes (consumer index is implicit). */
     dma_wdata.cndtr = ARRAY_SIZE(dma.buf);
@@ -645,6 +659,9 @@ static void floppy_write_prep(void)
         rw.status = ACK_WRPROT;
         floppy_state = ST_write_flux_drain;
     }
+
+    index.delay = time_sysclk(wf->index_delay_ticks);
+    rw.terminate_at_index = wf->terminate_at_index;
 }
 
 static void floppy_write_wait_data(void)
@@ -727,6 +744,10 @@ static void floppy_write(void)
     floppy_process_write_packet();
     wdata_decode_flux();
 
+    /* Early termination on index pulse? */
+    if (rw.terminate_at_index && (index.count != 0))
+        goto terminate;
+
     if (!rw.write_finished) {
         floppy_write_check_underflow();
         return;
@@ -735,15 +756,16 @@ static void floppy_write(void)
     /* Wait for DMA ring to drain. */
     todo = ~0;
     do {
-        /* Early termination on index pulse? */
-//        if (wr->terminate_at_index && (index.count != index_count))
-//            goto out;
+        /* Check for early termination on index pulse. */
+        if (rw.terminate_at_index && (index.count != 0))
+            goto terminate;
         /* Check progress of draining the DMA ring. */
         prev_todo = todo;
         dmacons = ARRAY_SIZE(dma.buf) - dma_wdata.cndtr;
         todo = (dma.prod - dmacons) & (ARRAY_SIZE(dma.buf) - 1);
     } while ((todo != 0) && (todo <= prev_todo));
 
+terminate:
     floppy_flux_end();
     floppy_state = ST_write_flux_drain;
 }
@@ -766,6 +788,13 @@ static void floppy_write_drain(void)
     floppy_state = ST_command_wait;
     floppy_end_command(u_buf, 1);
     drive_deselect();
+
+    /* Reset INDEX handling. */
+    IRQ_global_disable();
+    index.delay = 0;
+    IRQx_clear_pending(irq_index_delay);
+    timer_cancel(&index.delay_timer);
+    IRQ_global_enable();
 }
 
 static void process_command(void)
@@ -828,8 +857,10 @@ static void process_command(void)
         break;
     }
     case CMD_WRITE_FLUX: {
-        if (len != 2) goto bad_command;
-        floppy_write_prep();
+        struct gw_write_flux wf = { 0 };
+        if ((len < 2) || (len > (2 + sizeof(wf)))) goto bad_command;
+        memcpy(&wf, &u_buf[2], len-2);
+        floppy_write_prep(&wf);
         break;
     }
     case CMD_GET_FLUX_STATUS: {
@@ -936,13 +967,29 @@ const struct usb_class_ops usb_cdc_acm_ops = {
  * INTERRUPT HANDLERS
  */
 
+static void index_delay_timer(void *unused)
+{
+    index.count++;
+}
+
+static void IRQ_INDEX_delay(void)
+{
+    timer_set(&index.delay_timer, index.timestamp + index.delay);
+}
+
 static void IRQ_INDEX_changed(void)
 {
     /* Clear INDEX-changed flag. */
     exti->pr = m(pin_index);
 
-    index.count++;
     index.rdata_cnt = tim_rdata->cnt;
+    index.timestamp = time_now();
+
+    if (index.delay != 0) {
+        IRQx_set_pending(irq_index_delay);
+    } else {
+        index.count++;
+    }
 }
 
 /*