zy1000: fix non-JTAG master build
[openocd.git] / src / jtag / zy1000 / zy1000.c
index a1104ef4f31832bf7ae22b41d20080f57463eaf2..c8bee2f506292c282f03e4cb1271ebb7712b76fe 100644 (file)
@@ -62,6 +62,9 @@
 #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
@@ -70,6 +73,9 @@
 #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
 
 
@@ -84,7 +90,33 @@ static int zy1000_khz(int khz, int *jtag_speed)
        }
        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;
 }
@@ -97,7 +129,7 @@ static int zy1000_speed_div(int speed, int *khz)
        }
        else
        {
-               *khz = 64000/speed;
+               *khz = ZYLIN_KHZ / speed;
        }
 
        return ERROR_OK;
@@ -239,13 +271,17 @@ int zy1000_speed(int speed)
        {
                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;
 }
@@ -285,7 +321,7 @@ COMMAND_HANDLER(handle_power_command)
        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)
 {
@@ -463,6 +499,14 @@ int interface_jtag_execute_queue(void)
 
        waitIdle();
 
+       /* We must make sure to write data read back to memory location before we return
+        * from this fn
+        */
+       zy1000_flush_readqueue();
+
+       /* and handle any callbacks... */
+       zy1000_flush_callbackqueue();
+
        if (zy1000_rclk)
        {
                /* Only check for errors when using RCLK to speed up
@@ -487,38 +531,7 @@ int interface_jtag_execute_queue(void)
 
 
 
-
-static uint32_t getShiftValue(void)
-{
-       uint32_t value;
-       waitIdle();
-       ZY1000_PEEK(ZY1000_JTAG_BASE + 0xc, value);
-       VERBOSE(LOG_INFO("getShiftValue %08x", value));
-       return value;
-}
-#if 0
-static uint32_t getShiftValueFlip(void)
-{
-       uint32_t value;
-       waitIdle();
-       ZY1000_PEEK(ZY1000_JTAG_BASE + 0x18, value);
-       VERBOSE(LOG_INFO("getShiftValue %08x (flipped)", value));
-       return value;
-}
-#endif
-
-#if 0
-static void shiftValueInnerFlip(const tap_state_t state, const tap_state_t endState, int repeat, uint32_t value)
-{
-       VERBOSE(LOG_INFO("shiftValueInner %s %s %d %08x (flipped)", tap_state_name(state), tap_state_name(endState), repeat, value));
-       uint32_t a,b;
-       a = state;
-       b = endState;
-       ZY1000_POKE(ZY1000_JTAG_BASE + 0xc, value);
-       ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (1 << 15) | (repeat << 8) | (a << 4) | b);
-       VERBOSE(getShiftValueFlip());
-}
-#endif
+static void writeShiftValue(uint8_t *data, int bits);
 
 // here we shuffle N bits out/in
 static __inline void scanBits(const uint8_t *out_value, uint8_t *in_value, int num_bits, bool pause_now, tap_state_t shiftState, tap_state_t end_state)
@@ -562,15 +575,7 @@ static __inline void scanBits(const uint8_t *out_value, uint8_t *in_value, int n
 
                if (in_value != NULL)
                {
-                       // data in, LSB to MSB
-                       value = getShiftValue();
-                       // we're shifting in data to MSB, shift data to be aligned for returning the value
-                       value >>= 32-k;
-
-                       for (int l = 0; l < k; l += 8)
-                       {
-                               in_value[(j + l)/8]=(value >> l)&0xff;
-                       }
+                       writeShiftValue(in_value + (j/8), k);
                }
        }
 }
@@ -899,7 +904,7 @@ int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap * tap, uint32_t opc
 
        if ((pre_bits > 32) || (post_bits > 32))
        {
-               int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap * tap, uint32_t opcode, uint32_t * data, size_t count);
+               int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *, uint32_t, uint32_t *, size_t);
                return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count);
        } else
        {
@@ -997,6 +1002,7 @@ static const struct command_registration zy1000_commands[] = {
                        "With no arguments, prints status.",
                .usage = "('on'|'off)",
        },
+#if BUILD_ZY1000_MASTER
 #if BUILD_ECOSBOARD
        {
                .name = "zy1000_version",
@@ -1005,6 +1011,7 @@ static const struct command_registration zy1000_commands[] = {
                .help = "Print version info for zy1000.",
                .usage = "['openocd'|'zy1000'|'date'|'time'|'pcb'|'fpga']",
        },
+#endif
 #else
        {
                .name = "zy1000_server",
@@ -1033,6 +1040,7 @@ static const struct command_registration zy1000_commands[] = {
 };
 
 
+#if !BUILD_ZY1000_MASTER || BUILD_ECOSBOARD
 static int tcp_ip = -1;
 
 /* Write large packets if we can */
@@ -1101,16 +1109,18 @@ static bool readLong(uint32_t *out_data)
        *out_data = data;
        return true;
 }
+#endif
 
 enum ZY1000_CMD
 {
        ZY1000_CMD_POKE = 0x0,
        ZY1000_CMD_PEEK = 0x8,
        ZY1000_CMD_SLEEP = 0x1,
+       ZY1000_CMD_WAITIDLE = 2
 };
 
 
-#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() */
@@ -1167,9 +1177,26 @@ void zy1000_tcpout(uint32_t address, uint32_t data)
        }
 }
 
+/* By sending the wait to the server, we avoid a readback
+ * of status. Radically improves performance for this operation
+ * with long ping times.
+ */
+void waitIdle(void)
+{
+       tcpip_open();
+       if (!writeLong((ZY1000_CMD_WAITIDLE << 24)))
+       {
+               fprintf(stderr, "Could not write to zy1000 server\n");
+               exit(-1);
+       }
+}
+
 uint32_t zy1000_tcpin(uint32_t address)
 {
        tcpip_open();
+
+       zy1000_flush_readqueue();
+
        uint32_t data;
        if (!writeLong((ZY1000_CMD_PEEK << 24) | address)||
                        !readLong(&data))
@@ -1192,6 +1219,148 @@ int interface_jtag_add_sleep(uint32_t us)
        return ERROR_OK;
 }
 
+/* queue a readback */
+#define readqueue_size 16384
+static struct
+{
+       uint8_t *dest;
+       int bits;
+} readqueue[readqueue_size];
+
+static int readqueue_pos = 0;
+
+/* flush the readqueue, this means reading any data that
+ * we're expecting and store them into the final position
+ */
+void zy1000_flush_readqueue(void)
+{
+       if (readqueue_pos == 0)
+       {
+               /* simply debugging by allowing easy breakpoints when there
+                * is something to do. */
+               return;
+       }
+       int i;
+       tcpip_open();
+       for (i = 0; i < readqueue_pos; i++)
+       {
+               uint32_t value;
+               if (!readLong(&value))
+               {
+                       fprintf(stderr, "Could not read from zy1000 server\n");
+                       exit(-1);
+               }
+
+               uint8_t *in_value = readqueue[i].dest;
+               int k = readqueue[i].bits;
+
+               // we're shifting in data to MSB, shift data to be aligned for returning the value
+               value >>= 32-k;
+
+               for (int l = 0; l < k; l += 8)
+               {
+                       in_value[l/8]=(value >> l)&0xff;
+               }
+       }
+       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();
+
+       if (!writeLong((ZY1000_CMD_PEEK << 24) | (ZY1000_JTAG_BASE + 0xc)))
+       {
+               fprintf(stderr, "Could not read from zy1000 server\n");
+               exit(-1);
+       }
+
+       if (readqueue_pos >= readqueue_size)
+       {
+               zy1000_flush_readqueue();
+       }
+
+       readqueue[readqueue_pos].dest = data;
+       readqueue[readqueue_pos].bits = bits;
+       readqueue_pos++;
+}
+
+#else
+
+static void writeShiftValue(uint8_t *data, int bits)
+{
+       uint32_t value;
+       waitIdle();
+       ZY1000_PEEK(ZY1000_JTAG_BASE + 0xc, value);
+       VERBOSE(LOG_INFO("getShiftValue %08x", value));
+
+       // data in, LSB to MSB
+       // we're shifting in data to MSB, shift data to be aligned for returning the value
+       value >>= 32 - bits;
+
+       for (int l = 0; l < bits; l += 8)
+       {
+               data[l/8]=(value >> l)&0xff;
+       }
+}
 
 #endif
 
@@ -1241,6 +1410,11 @@ static void tcpipserver(void)
                                jtag_sleep(data);
                                break;
                        }
+                       case ZY1000_CMD_WAITIDLE:
+                       {
+                               waitIdle();
+                               break;
+                       }
                        default:
                                return;
                }
@@ -1396,21 +1570,49 @@ static void watchdog_server(cyg_addrword_t data)
 }
 #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
@@ -1453,4 +1655,3 @@ struct jtag_interface zy1000_interface =
        .power_dropout = zy1000_power_dropout,
        .srst_asserted = zy1000_srst_asserted,
 };
-

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)