]> rtime.felk.cvut.cz Git - fpga/lx-cpu1/lx-rocon.git/commitdiff
Update software for Tumbl interaction and debugging
authorMartin Meloun <meloumar@cmp.felk.cvut.cz>
Wed, 18 Sep 2013 14:22:52 +0000 (16:22 +0200)
committerMartin Meloun <meloumar@cmp.felk.cvut.cz>
Wed, 18 Sep 2013 14:22:52 +0000 (16:22 +0200)
sw/app/rocon/appl_fpga.c
sw/app/rocon/appl_fpga.h
sw/app/rocon/appl_usb.c

index ee9fa51b4a76d1f60151f2b19f2500f7de8fce04..67ed35bdf87350edf877925f73bb0850ad9c6484 100644 (file)
 #include "appl_version.h"
 #include "appl_fpga.h"
 
-volatile uint16_t *fpga_configure_line = 0x8003FFFC;
+#define SWAB32(x) ((x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24))
+
+/* Registers in FPGA */
+volatile uint32_t *tumbl_control = (volatile uint32_t *)FPGA_TUMBL_CONTROL_REG;
+volatile uint32_t *tumbl_trace_kick = (volatile uint32_t *)FPGA_TUMBL_TRACE_KICK_REG;
+volatile uint32_t *tumbl_pc = (volatile uint32_t *)FPGA_TUMBL_PC;
+volatile uint32_t *tumbl_base = (volatile uint32_t *)FPGA_TUMBL_IMEM_BASE;
+volatile uint32_t *tumbl_imem = (volatile uint32_t *)FPGA_TUMBL_IMEM_BASE;
+volatile uint32_t *tumbl_dmem = (volatile uint32_t *)FPGA_TUMBL_DMEM_BASE;
+
+volatile struct irc_register *irc1 = (volatile struct irc_register *)FPGA_IRC1_BASE;
+volatile struct irc_register *irc2 = (volatile struct irc_register *)FPGA_IRC2_BASE;
+volatile struct irc_register *irc3 = (volatile struct irc_register *)FPGA_IRC3_BASE;
+volatile struct irc_register *irc4 = (volatile struct irc_register *)FPGA_IRC4_BASE;
+
+/* Variables for configuration */
+volatile uint16_t *fpga_configure_line = (volatile uint16_t *)0x8003FFFC;
 int fpga_configured = 0;
 int fpga_reconfiguration_locked = 1;
 
+/* BUS calibration - registers to measure the delay necessary for reading and writing */
+volatile uint32_t *fpga_bus_calib_read1 = (volatile uint32_t *)0x8003FFF0;
+volatile uint32_t *fpga_bus_calib_read2 = (volatile uint32_t *)0x8003FFF4;
+
+volatile uint32_t *fpga_bus_calib_write1 = (volatile uint32_t *)0x8003FFF8;
+volatile uint32_t *fpga_bus_calib_write2 = (volatile uint32_t *)0x8003FFFC;
+
+/* BUS calibration - values (shifting all bits) */
+#define CALIB_VAL1 0xAAAAAAAA
+#define CALIB_VAL2 0x55555555
+
 void appl_fpga_init()
 {
   /* Initialze EMC for FPGA */
@@ -29,23 +56,226 @@ void appl_fpga_init()
   LPC_EMC->StaticConfig0 = 0x00000002;
 
   /* Delays - not calibrated at this point
-   * Read: use default: 32 cycles
-   * Write: use default: 33 cycles
-   * Turnaround: use default: 16 cycles
+   * We're running on 72 MHz, FPGA bus is running on 100 MHz async.
+   * Read: 32 cycles
+   * Write: 33 cycles
+   * Turnaround: 2 cycles (cca. 28 ns)
    */
+  LPC_EMC->StaticWaitRd0 = 0x1F;
+  LPC_EMC->StaticWaitWr0 = 0x1F;
+  LPC_EMC->StaticWaitTurn0 = 0x01;
 
   /* Shift addresses by 2 (32-bit bus) */
   LPC_SC->SCS &= 0xFFFFFFFE;
 
-  printf("EMC for FPGA configured!\n");
+  printf("EMC for FPGA initialized!\n");
+}
+
+int appl_fpga_tumbl_set_reset(int reset)
+{ 
+  int i;
+  
+  if (reset)
+    *tumbl_control |= FPGA_TUMBL_CONTROL_REG_RESET_BIT;
+  else
+    *tumbl_control &= ~FPGA_TUMBL_CONTROL_REG_RESET_BIT;
+  return 0;
+}
+
+int appl_fpga_tumbl_set_halt(int halt)
+{
+  if (halt)
+    *tumbl_control |= FPGA_TUMBL_CONTROL_REG_HALT_BIT; 
+  else
+    *tumbl_control &= ~FPGA_TUMBL_CONTROL_REG_HALT_BIT;
+  
+  return 0;
+}
+
+int appl_fpga_tumbl_set_trace(int trace)
+{  
+  if (trace)
+    *tumbl_control |= FPGA_TUMBL_CONTROL_REG_TRACE_BIT; 
+  else
+    *tumbl_control &= ~FPGA_TUMBL_CONTROL_REG_TRACE_BIT;
+  
+  return 0;
+}
+
+int appl_fpga_tumbl_kick_trace()
+{
+  int i;
+  
+  *tumbl_trace_kick = 1;
+  __memory_barrier();
+
+  /* Make sure it's processed */
+  for (i = 0; i < 32; i++)
+  {}
+  
+  __memory_barrier();
+  printf("Tumbl PC: 0x%08X\n", (unsigned int) *tumbl_pc);
+  return 0;
+}
+
+void appl_fpga_tumbl_write(unsigned int offset, unsigned char *ptr, int len)
+{
+  int i;
+  unsigned int *iptr = (unsigned int *)ptr;
+  
+  for (i = 0; i < len / 4; i++)
+    tumbl_base[(offset / 4) + i] = SWAB32(iptr[i]);
+}
+
+/* 
+ * Bus calibration - functions can be called via USB interface
+ * Proper usage:
+ * 1) Calibrate read
+ * 2) Calibrate write
+ * 3) Set turnaround
+ *      bus is not pipelined, therefore
+ *      just necessary delay for I/O to enter
+ *      high impedance state (synchronous clocking => only 1 cycle necessary)
+ */
+
+/* Cannot be on stack due to memory barrier for gcc */
+static uint32_t a, b;
+
+int appl_fpga_calibrate_bus_read()
+{
+  int i;
+  
+  /* Set the delays are set to highest (default) value */
+  LPC_EMC->StaticWaitRd0 = 0x1F;
+  
+  while (LPC_EMC->StaticWaitRd0 >= 0)
+  {
+    for (i = 0; i < 1024; i++)
+    {
+      /* Reset the values */
+      __memory_barrier();
+      a = 0xFFFFFFFF;
+      b = 0xFFFFFFFF;
+      __memory_barrier();
+      /* Read the values several times - so there are two flips at least
+       * NOTE: SDRAM reads / writes may occur in between!
+       */
+      a = *fpga_bus_calib_read1;
+      b = *fpga_bus_calib_read2;
+      a = *fpga_bus_calib_read1;
+      b = *fpga_bus_calib_read2;
+      a = *fpga_bus_calib_read1;
+      b = *fpga_bus_calib_read2;
+      a = *fpga_bus_calib_read1;
+      b = *fpga_bus_calib_read2;
+      __memory_barrier();
+      
+      /* Verify */
+      if (a != CALIB_VAL1 || b != CALIB_VAL2)
+      {
+        if (LPC_EMC->StaticWaitRd0 == 0x1F)
+        {
+          printf("ERROR: FPGA bus is not working properly!\n"); 
+          return 1;
+        }
+        else
+        {
+          LPC_EMC->StaticWaitRd0++;
+          printf("FPGA bus: StaticWaitRd0 set to 0x%02X\n", (unsigned int) LPC_EMC->StaticWaitRd0);
+          return 0;
+        }
+      }
+    }
+    
+    /* We're good, lower it */
+    if (LPC_EMC->StaticWaitRd0 == 0)
+    {
+      printf("FPGA bus: StaticWaitRd0 set to 0x%02X\n", (unsigned int) LPC_EMC->StaticWaitRd0);
+      break;
+    }
+    else
+      LPC_EMC->StaticWaitRd0--;
+  }
+
+  return 0;
 }
 
-void appl_fpga_set_reconfiguartion_lock(int lock)
+int appl_fpga_calibrate_bus_write()
+{
+  int i;
+  
+  /* Set the delays are set to highest (default) value */
+  LPC_EMC->StaticWaitWr0 = 0x1F;
+
+  while (LPC_EMC->StaticWaitWr0 >= 0)
+  {
+    for (i = 0; i < 1024; i++)
+    {
+      /* Make sure there is nothing other going on */
+      __memory_barrier();
+      *fpga_bus_calib_write1 = 0x00000000;
+      *fpga_bus_calib_write2 = 0x00000000;
+      __memory_barrier();
+      a = 0xFFFFFFFF;
+      b = 0xFFFFFFFF;
+      __memory_barrier();
+      /* Write the values several times - so there are two flips at least
+       * NOTE: SDRAM reads / writes may occur in between!
+       */
+      *fpga_bus_calib_write1 = CALIB_VAL1;
+      *fpga_bus_calib_write2 = CALIB_VAL2;
+      *fpga_bus_calib_write1 = CALIB_VAL1;
+      *fpga_bus_calib_write2 = CALIB_VAL2;
+      *fpga_bus_calib_write1 = CALIB_VAL1;
+      *fpga_bus_calib_write2 = CALIB_VAL2;
+      *fpga_bus_calib_write1 = CALIB_VAL1;
+      *fpga_bus_calib_write2 = CALIB_VAL2;
+      /* 
+       * Strongly ordered memory
+       * GCC is blocked by volatilness
+       */
+      __memory_barrier();
+      a = *fpga_bus_calib_write1;
+      b = *fpga_bus_calib_write2;
+      __memory_barrier();
+      
+      /* Verify */
+      if (a != CALIB_VAL1 || b != CALIB_VAL2)
+      {
+        if (LPC_EMC->StaticWaitWr0 == 0x1F)
+        {
+          printf("ERROR: FPGA bus is not working properly!\n");
+          printf("a = 0x%08X, b = 0x%08X\n", (unsigned int) a, (unsigned int) b);
+          return 1;
+        }
+        else
+        {
+          LPC_EMC->StaticWaitWr0++;
+          printf("FPGA bus: StaticWaitWr0 set to 0x%02X\n", (unsigned int) LPC_EMC->StaticWaitWr0);
+          return 0;
+        }
+      }
+    }
+    
+    /* We're good, lower it */
+    if (LPC_EMC->StaticWaitWr0 == 0)
+    {
+      printf("FPGA bus: StaticWaitWr0 set to 0x%02X\n", (unsigned int) LPC_EMC->StaticWaitWr0);
+      break;
+    }
+    else
+      LPC_EMC->StaticWaitWr0--;
+  }
+
+  return 0;
+}
+
+void appl_fpga_set_reconfiguration_lock(int lock)
 {
   fpga_reconfiguration_locked = lock;
 }
 
-int appl_fpga_get_reconfiguartion_lock()
+int appl_fpga_get_reconfiguration_lock()
 {
   return fpga_reconfiguration_locked;
 }
@@ -89,6 +319,10 @@ int appl_fpga_configure()
 
     j++;
   }
+  
+  /* Use highest EMC delays */
+  LPC_EMC->StaticWaitRd0 = 0x1F;
+  LPC_EMC->StaticWaitWr0 = 0x1F;
 
   /* Assert RWDR to WRITE */
   hal_gpio_set_value(XC_RDWR_PIN, 0);
@@ -161,7 +395,7 @@ int appl_fpga_configure()
     }
   }
 
-  /* Issue startup clocks with data in all 1 (at least 8 recommended) */
+  /* Issue startup clocks with data all 1s (at least 8 recommended) */
   for (i = 0; i < 16; i++)
     *fpga_configure_line = 0xFFFF;
 
@@ -171,9 +405,18 @@ int appl_fpga_configure()
   /* Hold it for some time */
   for (i = 0; i < 128; i++)
     {}
+    
+  /* Use EMC delays obtained through calibration */
+  LPC_EMC->StaticWaitRd0 = 0x04;
+  LPC_EMC->StaticWaitWr0 = 0x01;
 
   /* Lift the reset */
   hal_gpio_direction_output(XC_INIT_PIN, 1);
+  
+   /* Give it some time */
+  for (i = 0; i < 1024; i++)
+    {}
+  
   fpga_configured = 1;
   printf("FPGA configured!\n");
   return FPGA_CONF_SUCESS;
index 2005efcaa786359e6875edfc0f5d4bc8ce25986d..738c5777b066a13c8032ea452478a049669255ac 100644 (file)
@@ -3,6 +3,49 @@
 
 #include "appl_defs.h"
 
+/* Register defines */
+
+/* Tumbl */
+
+#define FPGA_TUMBL_IMEM_BASE      0x80000000
+#define FPGA_TUMBL_DMEM_BASE      0x80001000
+#define FPGA_TUMBL_CONTROL_REG    0x80003000
+#define FPGA_TUMBL_TRACE_KICK_REG 0x80003004
+#define FPGA_TUMBL_PC             0x80003008
+
+#define FPGA_TUMBL_CONTROL_REG_RESET_BIT 0x01
+#define FPGA_TUMBL_CONTROL_REG_INT_BIT   0x02
+#define FPGA_TUMBL_CONTROL_REG_HALT_BIT  0x04
+#define FPGA_TUMBL_CONTROL_REG_TRACE_BIT 0x08
+
+extern volatile uint32_t *tumbl_control;
+extern volatile uint32_t *tumbl_trace_kick;
+extern volatile uint32_t *tumbl_imem;
+extern volatile uint32_t *tumbl_dmem;
+
+/* IRC */
+
+#define FPGA_IRC1_BASE    0x80020000
+#define FPGA_IRC2_BASE    0x80020010
+#define FPGA_IRC3_BASE    0x80020020
+#define FPGA_IRC4_BASE    0x80020030
+
+struct irc_register
+{
+  uint32_t count;
+  uint32_t count_index;
+  uint32_t state;
+};
+
+extern volatile struct irc_register *irc1;
+extern volatile struct irc_register *irc2;
+extern volatile struct irc_register *irc3;
+extern volatile struct irc_register *irc4;
+
+extern volatile uint32_t *fpga_bcd;
+
+/* Configuration defines */
+
 #define FPGA_CONFIGURATION_FILE_ADDRESS 0xA1C00000
 
 #define FPGA_CONF_SUCESS              0
 #define FPGA_CONF_ERR_WRITE_ERR       3
 #define FPGA_CONF_ERR_CRC_ERR         4
 
+int appl_fpga_tumbl_set_reset(int reset);
+int appl_fpga_tumbl_set_halt(int halt);
+int appl_fpga_tumbl_set_trace(int trace);
+int appl_fpga_tumbl_kick_trace();
+
+void appl_fpga_tumbl_write(unsigned int offset, unsigned char *ptr, int len);
+
 void appl_fpga_init();
 int appl_fpga_configure();
-void appl_fpga_set_reconfiguartion_lock(int lock);
-int appl_fpga_get_reconfiguartion_lock();
+int appl_fpga_calibrate_bus_read();
+int appl_fpga_calibrate_bus_write();
+void appl_fpga_set_reconfiguration_lock(int lock);
+int appl_fpga_get_reconfiguration_lock();
 
 #endif /*_APPL_FPGA_H*/
index 72500132d28e9e029ea27a8bcaa771a7227c3e8c..b3bb8a0234ef1824f3b2bb3997f091923da5b0ae 100644 (file)
 #define SWAP(x) (x)
 #endif
 
-#define USB_CMD_FPGA_CONFIGURE 0xF000
+#define USB_VENDOR_TARGET_TUMBL       0x03
+
+#define USB_CMD_FPGA_CONFIGURE        0xF000
+#define USB_CMD_FPGA_CALIBRATE_READ   0xF001
+#define USB_CMD_FPGA_CALIBRATE_WRITE  0xF002
+#define USB_CMD_FPGA_TEST_IRC         0xF004
+#define USB_CMD_FPGA_TEST_BCD         0xF005
+
+#define USB_CMD_FPGA_TUMBL_SET_RESET  0xF100
+#define USB_CMD_FPGA_TUMBL_SET_HALT   0xF101
+#define USB_CMD_FPGA_TUMBL_SET_TRACE  0xF102
+#define USB_CMD_FPGA_TUMBL_KICK_TRACE 0xF103
+
+#define USB_CMD_FPGA_TUMBL_DUMP_IMEM  0xF200
+#define USB_CMD_FPGA_TUMBL_DUMP_DMEM  0xF201
+
+#define USB_CMD_FPGA_RESET            0xFFFF
 
 usb_device_t usb_device;
 usb_ep_t eps[NUM_ENDPOINTS];
@@ -119,6 +135,17 @@ static int usb_flash_pkt_wr(struct usb_ep_t *ep, int len, int code)
   return USB_COMPLETE_OK;
 }
 
+static int usb_tumbl_pkt_wr(struct usb_ep_t *ep, int len, int code)
+{
+  unsigned char *ptr = ep->ptr - len;
+  
+  appl_fpga_tumbl_write(ep->user_data, ptr, len);
+  
+  ep->user_data += len;
+  ep->ptr = ep0_buffer;
+  return USB_COMPLETE_OK;
+}
+
 static int usb_flash_erase(unsigned addr, unsigned len)
 {
 #ifdef CONFIG_KEYVAL
@@ -144,8 +171,69 @@ uint16_t vendor_call_ret = 0xFFFF;
 
 uint16_t appl_usb_vendor_call(uint16_t command, uint16_t argument)
 {
-  if (command == USB_CMD_FPGA_CONFIGURE)
-    return appl_fpga_configure();
+  int i, j;
+  
+  switch (command)
+  {
+    case USB_CMD_FPGA_CONFIGURE:
+      return appl_fpga_configure();
+
+    case USB_CMD_FPGA_CALIBRATE_READ:
+      return appl_fpga_calibrate_bus_read();
+
+    case USB_CMD_FPGA_CALIBRATE_WRITE:
+      return appl_fpga_calibrate_bus_write();
+
+    case USB_CMD_FPGA_TEST_IRC:
+      printf("IRC1: count = %d, count index = %d\n", (unsigned int) irc1->count, (unsigned int) irc1->count_index);
+      printf("IRC2: count = %d, count index = %d\n", (unsigned int) irc2->count, (unsigned int) irc2->count_index);
+      printf("IRC3: count = %d, count index = %d\n", (unsigned int) irc3->count, (unsigned int) irc3->count_index);
+      printf("IRC4: count = %d, count index = %d\n", (unsigned int) irc4->count, (unsigned int) irc4->count_index);
+      return 0;
+
+    case USB_CMD_FPGA_TUMBL_SET_RESET:
+      return appl_fpga_tumbl_set_reset(argument);
+    
+    case USB_CMD_FPGA_TUMBL_SET_HALT:
+      return appl_fpga_tumbl_set_halt(argument);
+    
+    case USB_CMD_FPGA_TUMBL_SET_TRACE:
+      return appl_fpga_tumbl_set_trace(argument);
+      
+    case USB_CMD_FPGA_TUMBL_KICK_TRACE:
+      return appl_fpga_tumbl_kick_trace();
+    
+    case USB_CMD_FPGA_TUMBL_DUMP_IMEM:
+      printf("TUMBL IMEM:\n");
+      for (i = 0; i < 64; i++)
+      {        
+        for (j = 0; j < 8; j++)
+          printf("%08X ", (unsigned int) tumbl_imem[i*8 + j]);
+          
+        printf("\n");
+      }
+      return 0;
+      
+    case USB_CMD_FPGA_TUMBL_DUMP_DMEM:
+      printf("TUMBL DMEM:\n");
+      for (i = 0; i < 128; i++)
+      {
+        for (j = 0; j < 8; j++)
+          printf("%08X ", (unsigned int) tumbl_dmem[i*8 + j]);
+          
+        printf("\n");
+      }
+      return 0;
+      
+    case USB_CMD_FPGA_RESET:
+      hal_gpio_direction_output(XC_INIT_PIN, 0);
+
+      for (i = 0; i < 128; i++)
+        {}
+
+      hal_gpio_direction_output(XC_INIT_PIN, 1);
+      return 0;
+  }
 
   return 0xFFFF;
 }
@@ -223,6 +311,12 @@ int appl_usb_vendor(usb_device_t *udev)
             udev->ep0.user_data = addr;
             udev->ep0.ptr = ep0_buffer;
             break;
+            
+          case USB_VENDOR_TARGET_TUMBL:
+            udev->ep0.next_pkt_fnc = usb_tumbl_pkt_wr;
+            udev->ep0.user_data = addr;
+            udev->ep0.ptr = ep0_buffer;
+            break;
 
           default:
             return -1;