#ifdef CYGPKG_HAL_NIOS2
#include <cyg/hal/io.h>
#include <cyg/firmwareutil/firmwareutil.h>
+#define ZYLIN_KHZ 60000
+#else
+#define ZYLIN_KHZ 64000
#endif
#define ZYLIN_VERSION GIT_ZY1000_VERSION
#define ZYLIN_OPENOCD GIT_OPENOCD_VERSION
#define ZYLIN_OPENOCD_VERSION "ZY1000 " ZYLIN_VERSION " " ZYLIN_DATE
+#else
+/* Assume we're connecting to a revc w/60MHz clock. */
+#define ZYLIN_KHZ 60000
#endif
}
else
{
- *jtag_speed = 64000/khz;
+ int speed;
+ /* Round speed up to nearest divisor.
+ *
+ * E.g. 16000kHz
+ * (64000 + 15999) / 16000 = 4
+ * (4 + 1) / 2 = 2
+ * 2 * 2 = 4
+ *
+ * 64000 / 4 = 16000
+ *
+ * E.g. 15999
+ * (64000 + 15998) / 15999 = 5
+ * (5 + 1) / 2 = 3
+ * 3 * 2 = 6
+ *
+ * 64000 / 6 = 10666
+ *
+ */
+ speed = (ZYLIN_KHZ + (khz -1)) / khz;
+ speed = (speed + 1 ) / 2;
+ speed *= 2;
+ if (speed > 8190)
+ {
+ /* maximum dividend */
+ speed = 8190;
+ }
+ *jtag_speed = speed;
}
return ERROR_OK;
}
}
else
{
- *khz = 64000/speed;
+ *khz = ZYLIN_KHZ / speed;
}
return ERROR_OK;
{
if (speed > 8190 || speed < 2)
{
- LOG_USER("valid ZY1000 jtag_speed=[8190,2]. Divisor is 64MHz / even values between 8190-2, i.e. min 7814Hz, max 32MHz");
+ LOG_USER("valid ZY1000 jtag_speed=[8190,2]. With divisor is %dkHz / even values between 8190-2, i.e. min %dHz, max %dMHz",
+ ZYLIN_KHZ, (ZYLIN_KHZ * 1000) / 8190, ZYLIN_KHZ / (2 * 1000));
return ERROR_INVALID_ARGUMENTS;
}
- LOG_USER("jtag_speed %d => JTAG clk=%f", speed, 64.0/(float)speed);
+ int khz;
+ speed &= ~1;
+ zy1000_speed_div(speed, &khz);
+ LOG_USER("jtag_speed %d => JTAG clk=%d kHz", speed, khz);
ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x100);
- ZY1000_POKE(ZY1000_JTAG_BASE + 0x1c, speed&~1);
+ ZY1000_POKE(ZY1000_JTAG_BASE + 0x1c, speed);
}
return ERROR_OK;
}
return ERROR_OK;
}
-#if !BUILD_ECOSBOARD
+#if !BUILD_ZY1000_MASTER
static char *tcp_server = "notspecified";
static int jim_zy1000_server(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
*/
zy1000_flush_readqueue();
+ /* and handle any callbacks... */
+ zy1000_flush_callbackqueue();
+
if (zy1000_rclk)
{
/* Only check for errors when using RCLK to speed up
"With no arguments, prints status.",
.usage = "('on'|'off)",
},
+#if BUILD_ZY1000_MASTER
#if BUILD_ECOSBOARD
{
.name = "zy1000_version",
.help = "Print version info for zy1000.",
.usage = "['openocd'|'zy1000'|'date'|'time'|'pcb'|'fpga']",
},
+#endif
#else
{
.name = "zy1000_server",
};
+#if !BUILD_ZY1000_MASTER || BUILD_ECOSBOARD
static int tcp_ip = -1;
/* Write large packets if we can */
*out_data = data;
return true;
}
+#endif
enum ZY1000_CMD
{
};
-#if !BUILD_ECOSBOARD
+#if !BUILD_ZY1000_MASTER
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
#include <arpa/inet.h> /* for sockaddr_in and inet_addr() */
readqueue_pos = 0;
}
+/* By queuing the callback's we avoid flushing the
+read queue until jtag_execute_queue(). This can
+reduce latency dramatically for cases where
+callbacks are used extensively.
+*/
+#define callbackqueue_size 128
+static struct callbackentry
+{
+ jtag_callback_t callback;
+ jtag_callback_data_t data0;
+ jtag_callback_data_t data1;
+ jtag_callback_data_t data2;
+ jtag_callback_data_t data3;
+} callbackqueue[callbackqueue_size];
+
+static int callbackqueue_pos = 0;
+
+void zy1000_jtag_add_callback4(jtag_callback_t callback, jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3)
+{
+ if (callbackqueue_pos >= callbackqueue_size)
+ {
+ zy1000_flush_callbackqueue();
+ }
+
+ callbackqueue[callbackqueue_pos].callback = callback;
+ callbackqueue[callbackqueue_pos].data0 = data0;
+ callbackqueue[callbackqueue_pos].data1 = data1;
+ callbackqueue[callbackqueue_pos].data2 = data2;
+ callbackqueue[callbackqueue_pos].data3 = data3;
+ callbackqueue_pos++;
+}
+
+static int zy1000_jtag_convert_to_callback4(jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3)
+{
+ ((jtag_callback1_t)data1)(data0);
+ return ERROR_OK;
+}
+
+void zy1000_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0)
+{
+ zy1000_jtag_add_callback4(zy1000_jtag_convert_to_callback4, data0, (jtag_callback_data_t)callback, 0, 0);
+}
+
+void zy1000_flush_callbackqueue(void)
+{
+ /* we have to flush the read queue so we have access to
+ the data the callbacks will use
+ */
+ zy1000_flush_readqueue();
+ int i;
+ for (i = 0; i < callbackqueue_pos; i++)
+ {
+ struct callbackentry *entry = &callbackqueue[i];
+ jtag_set_error(entry->callback(entry->data0, entry->data1, entry->data2, entry->data3));
+ }
+ callbackqueue_pos = 0;
+}
+
static void writeShiftValue(uint8_t *data, int bits)
{
waitIdle();
}
#endif
+#endif
+
+#if BUILD_ZY1000_MASTER
int interface_jtag_add_sleep(uint32_t us)
{
jtag_sleep(us);
return ERROR_OK;
}
-
#endif
+#if BUILD_ZY1000_MASTER && !BUILD_ECOSBOARD
+volatile void *zy1000_jtag_master;
+#include <sys/mman.h>
+#endif
int zy1000_init(void)
{
#if BUILD_ECOSBOARD
LOG_USER("%s", ZYLIN_OPENOCD_VERSION);
+#elif BUILD_ZY1000_MASTER
+ int fd;
+ if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1)
+ {
+ LOG_ERROR("No access to /dev/mem");
+ return ERROR_FAIL;
+ }
+#ifndef REGISTERS_BASE
+#define REGISTERS_BASE 0x9002000
+#define REGISTERS_SPAN 128
+#endif
+
+ zy1000_jtag_master = mmap(0, REGISTERS_SPAN, PROT_READ | PROT_WRITE, MAP_SHARED, fd, REGISTERS_BASE);
+
+ if(zy1000_jtag_master == (void *) -1)
+ {
+ close(fd);
+ LOG_ERROR("No access to /dev/mem");
+ return ERROR_FAIL;
+ }
#endif
+
+
ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x30); // Turn on LED1 & LED2
setPower(true); // on by default