openrisc: add support for JTAG Serial Port 62/2162/3
authorFranck Jullien <franck.jullien@gmail.com>
Fri, 30 May 2014 14:49:42 +0000 (16:49 +0200)
committerAndreas Fritiofson <andreas.fritiofson@gmail.com>
Sun, 22 Jun 2014 08:39:08 +0000 (08:39 +0000)
Change-Id: I623a8c74bcca2edb5f996b69c02d73a6f67b7d34
Signed-off-by: Franck Jullien <franck.jullien@gmail.com>
Reviewed-on: http://openocd.zylin.com/2162
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
src/server/server.c
src/target/openrisc/Makefile.am
src/target/openrisc/jsp_server.c [new file with mode: 0644]
src/target/openrisc/jsp_server.h [new file with mode: 0644]
src/target/openrisc/or1k_du.h
src/target/openrisc/or1k_du_adv.c
tcl/board/or1k_generic.cfg
tcl/target/or1k.cfg

index 5169319c54905d0b8886ae7ccebf683374652189..7fbceb19a71fb3d32e899b506dfeb7ef3a9d2411 100644 (file)
@@ -31,6 +31,7 @@
 #include "server.h"
 #include <target/target.h>
 #include <target/target_request.h>
+#include <target/openrisc/jsp_server.h>
 #include "openocd.h"
 #include "tcl_server.h"
 #include "telnet_server.h"
@@ -46,6 +47,9 @@ static struct service *services;
 /* shutdown_openocd == 1: exit the main event loop, and quit the debugger */
 static int shutdown_openocd;
 
+/* set the polling period to 100ms */
+static int polling_period = 100;
+
 static int add_connection(struct service *service, struct command_context *cmd_ctx)
 {
        socklen_t address_size;
@@ -380,8 +384,8 @@ int server_loop(struct command_context *command_context)
                        tv.tv_usec = 0;
                        retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv);
                } else {
-                       /* Every 100ms */
-                       tv.tv_usec = 100000;
+                       /* Every 100ms, can be changed with "poll_period" command */
+                       tv.tv_usec = polling_period * 1000;
                        /* Only while we're sleeping we'll let others run */
                        openocd_sleep_prelude();
                        kept_alive();
@@ -588,6 +592,18 @@ COMMAND_HANDLER(handle_shutdown_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(handle_poll_period_command)
+{
+       if (CMD_ARGC == 0)
+               LOG_WARNING("You need to set a period value");
+       else
+               COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], polling_period);
+
+       LOG_INFO("set servers polling period to %ums", polling_period);
+
+       return ERROR_OK;
+}
+
 static const struct command_registration server_command_handlers[] = {
        {
                .name = "shutdown",
@@ -596,6 +612,13 @@ static const struct command_registration server_command_handlers[] = {
                .usage = "",
                .help = "shut the server down",
        },
+       {
+               .name = "poll_period",
+               .handler = &handle_poll_period_command,
+               .mode = COMMAND_ANY,
+               .usage = "",
+               .help = "set the servers polling period",
+       },
        COMMAND_REGISTRATION_DONE
 };
 
@@ -609,6 +632,10 @@ int server_register_commands(struct command_context *cmd_ctx)
        if (ERROR_OK != retval)
                return retval;
 
+       retval = jsp_register_commands(cmd_ctx);
+       if (ERROR_OK != retval)
+               return retval;
+
        return register_commands(cmd_ctx, NULL, server_command_handlers);
 }
 
index f1e7eaadf4f7c0f94ebe29aed508c02c9a78b944..b00a30d6f966dc2c4c6deef1410175937a6d5dfe 100644 (file)
@@ -8,9 +8,11 @@ OPENRISC_SRC = \
        or1k_du_adv.c \
        or1k_tap_mohor.c \
        or1k_tap_vjtag.c \
-       or1k_tap_xilinx_bscan.c
+       or1k_tap_xilinx_bscan.c \
+       jsp_server.c
 
 noinst_HEADERS = \
        or1k.h \
        or1k_du.h \
-       or1k_tap.h
+       or1k_tap.h \
+       jsp_server.h
diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c
new file mode 100644 (file)
index 0000000..597bfcb
--- /dev/null
@@ -0,0 +1,247 @@
+/***************************************************************************
+ *   Copyright (C) 2014 by Franck Jullien                                  *
+ *   franck.jullien@gmail.com                                              *
+ *                                                                         *
+ *   Based on ./src/server/telnet_server.c                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <server/telnet_server.h>
+
+#include "or1k_tap.h"
+#include "or1k_du.h"
+#include "jsp_server.h"
+
+static char *jsp_port;
+
+/**A skim of the relevant RFCs suggests that if my application simply sent the
+ * characters IAC DONT LINEMODE (\377\376\042) as soon as the client connects,
+ * the client should be forced into character mode. However it doesn't make any difference.
+ */
+
+static char *negotiate =
+       "\xFF\xFB\x03"                  /* IAC WILL Suppress Go Ahead */
+       "\xFF\xFB\x01"                  /* IAC WILL Echo */
+       "\xFF\xFD\x03"                  /* IAC DO Suppress Go Ahead */
+       "\xFF\xFE\x01";                 /* IAC DON'T Echo */
+
+/* The only way we can detect that the socket is closed is the first time
+ * we write to it, we will fail. Subsequent write operations will
+ * succeed. Shudder!
+ */
+static int telnet_write(struct connection *connection, const void *data, int len)
+{
+       struct telnet_connection *t_con = connection->priv;
+       if (t_con->closed)
+               return ERROR_SERVER_REMOTE_CLOSED;
+
+       if (connection_write(connection, data, len) == len)
+               return ERROR_OK;
+       t_con->closed = 1;
+       return ERROR_SERVER_REMOTE_CLOSED;
+}
+
+int jsp_poll_read(void *priv)
+{
+       struct jsp_service *jsp_service = (struct jsp_service *)priv;
+       unsigned char out_buffer[10];
+       unsigned char in_buffer[10];
+       int out_len = 0;
+       int in_len;
+
+       if (!jsp_service->connection)
+               return ERROR_FAIL;
+
+       memset(out_buffer, 0, 10);
+
+       or1k_adv_jtag_jsp_xfer(jsp_service->jtag_info, &out_len, out_buffer, &in_len, in_buffer);
+       if (in_len)
+               telnet_write(jsp_service->connection, in_buffer, in_len);
+
+       return ERROR_OK;
+}
+
+static int jsp_new_connection(struct connection *connection)
+{
+       struct telnet_connection *telnet_connection = malloc(sizeof(struct telnet_connection));
+       struct jsp_service *jsp_service = connection->service->priv;
+
+       connection->priv = telnet_connection;
+
+       /* initialize telnet connection information */
+       telnet_connection->closed = 0;
+       telnet_connection->line_size = 0;
+       telnet_connection->line_cursor = 0;
+       telnet_connection->option_size = 0;
+       telnet_connection->state = TELNET_STATE_DATA;
+
+       /* negotiate telnet options */
+       telnet_write(connection, negotiate, strlen(negotiate));
+
+       /* print connection banner */
+       if (jsp_service->banner) {
+               telnet_write(connection, jsp_service->banner, strlen(jsp_service->banner));
+               telnet_write(connection, "\r\n", 2);
+       }
+
+       jsp_service->connection = connection;
+
+       int retval = target_register_timer_callback(&jsp_poll_read, 1, 1, jsp_service);
+       if (ERROR_OK != retval)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static int jsp_input(struct connection *connection)
+{
+       int bytes_read;
+       unsigned char buffer[TELNET_BUFFER_SIZE];
+       unsigned char *buf_p;
+       struct telnet_connection *t_con = connection->priv;
+       struct jsp_service *jsp_service = connection->service->priv;
+
+       bytes_read = connection_read(connection, buffer, TELNET_BUFFER_SIZE);
+
+       if (bytes_read == 0)
+               return ERROR_SERVER_REMOTE_CLOSED;
+       else if (bytes_read == -1) {
+               LOG_ERROR("error during read: %s", strerror(errno));
+               return ERROR_SERVER_REMOTE_CLOSED;
+       }
+
+       buf_p = buffer;
+       while (bytes_read) {
+               switch (t_con->state) {
+                       case TELNET_STATE_DATA:
+                               if (*buf_p == 0xff)
+                                       t_con->state = TELNET_STATE_IAC;
+                               else {
+                                       int out_len = 1;
+                                       int in_len;
+                                       unsigned char in_buffer[10];
+                                       or1k_adv_jtag_jsp_xfer(jsp_service->jtag_info,
+                                                              &out_len, buf_p, &in_len,
+                                                              in_buffer);
+                                       if (in_len)
+                                               telnet_write(connection,
+                                                            in_buffer, in_len);
+                               }
+                               break;
+                       case TELNET_STATE_IAC:
+                               switch (*buf_p) {
+                               case 0xfe:
+                                       t_con->state = TELNET_STATE_DONT;
+                                       break;
+                               case 0xfd:
+                                       t_con->state = TELNET_STATE_DO;
+                                       break;
+                               case 0xfc:
+                                       t_con->state = TELNET_STATE_WONT;
+                                       break;
+                               case 0xfb:
+                                       t_con->state = TELNET_STATE_WILL;
+                                       break;
+                               }
+                               break;
+                       case TELNET_STATE_SB:
+                               break;
+                       case TELNET_STATE_SE:
+                               break;
+                       case TELNET_STATE_WILL:
+                       case TELNET_STATE_WONT:
+                       case TELNET_STATE_DO:
+                       case TELNET_STATE_DONT:
+                               t_con->state = TELNET_STATE_DATA;
+                               break;
+                       default:
+                               LOG_ERROR("unknown telnet state");
+                               exit(-1);
+               }
+
+               bytes_read--;
+               buf_p++;
+       }
+
+       return ERROR_OK;
+}
+
+static int jsp_connection_closed(struct connection *connection)
+{
+       struct telnet_connection *t_con = connection->priv;
+       struct jsp_service *jsp_service = connection->service->priv;
+
+       if (t_con->prompt) {
+               free(t_con->prompt);
+               t_con->prompt = NULL;
+       }
+
+       int retval = target_unregister_timer_callback(&jsp_poll_read, jsp_service);
+       if (ERROR_OK != retval)
+               return retval;
+
+       if (connection->priv) {
+               free(connection->priv);
+               connection->priv = NULL;
+       } else
+               LOG_ERROR("BUG: connection->priv == NULL");
+
+       return ERROR_OK;
+}
+
+int jsp_init(struct or1k_jtag *jtag_info, char *banner)
+{
+       struct jsp_service *jsp_service = malloc(sizeof(struct jsp_service));
+       jsp_service->banner = banner;
+       jsp_service->jtag_info = jtag_info;
+
+       return add_service("jsp",
+               jsp_port,
+               1,
+               jsp_new_connection,
+               jsp_input,
+               jsp_connection_closed,
+               jsp_service);
+}
+
+COMMAND_HANDLER(handle_jsp_port_command)
+{
+       return CALL_COMMAND_HANDLER(server_pipe_command, &jsp_port);
+}
+
+static const struct command_registration jsp_command_handlers[] = {
+       {
+               .name = "jsp_port",
+               .handler = handle_jsp_port_command,
+               .mode = COMMAND_ANY,
+               .help = "Specify port on which to listen "
+                       "for incoming JSP telnet connections.",
+               .usage = "[port_num]",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+int jsp_register_commands(struct command_context *cmd_ctx)
+{
+       jsp_port = strdup("7777");
+       return register_commands(cmd_ctx, NULL, jsp_command_handlers);
+}
+
diff --git a/src/target/openrisc/jsp_server.h b/src/target/openrisc/jsp_server.h
new file mode 100644 (file)
index 0000000..3e7c114
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _JSP_SERVER_H_
+#define _JSP_SERVER_H_
+
+#include "or1k_tap.h"
+#include "or1k.h"
+#include "or1k_du.h"
+
+struct jsp_service {
+       char *banner;
+       struct or1k_jtag *jtag_info;
+       struct connection *connection;
+};
+
+int jsp_init(struct or1k_jtag *jtag_info, char *banner);
+int jsp_register_commands(struct command_context *cmd_ctx);
+
+#endif /* _JSP_SERVER_H_ */
index 564241d8c9885be1208471782ceab81e6165be16..f5ee3643558e97071744ce319dd73c8fff7b141e 100644 (file)
@@ -73,5 +73,9 @@ static inline struct or1k_du *or1k_to_du(struct or1k_common *or1k)
        return (struct or1k_du *)jtag->du_core;
 }
 
+int or1k_adv_jtag_jsp_xfer(struct or1k_jtag *jtag_info,
+                                 int *out_len, unsigned char *out_buffer,
+                                 int *in_len, unsigned char *in_buffer);
+
 #endif
 
index 8a5562f0978897b6380b87b8f37a2754341bfdc5..e25a711b8ace7e9a42b48d3e49d529a3855fdbd9 100644 (file)
@@ -1,8 +1,8 @@
 /***************************************************************************
- *   Copyright (C) 2013 by Franck Jullien                                  *
+ *   Copyright (C) 2013-2014 by Franck Jullien                             *
  *   elec4fun@gmail.com                                                    *
  *                                                                         *
- *   Inspired from adv_jtag_bridge which is:                                *
+ *   Inspired from adv_jtag_bridge which is:                               *
  *   Copyright (C) 2008-2010 Nathan Yawn                                   *
  *   nyawn@opencores.net                                                   *
  *                                                                         *
 #include "or1k_tap.h"
 #include "or1k.h"
 #include "or1k_du.h"
+#include "jsp_server.h"
 
 #include <target/target.h>
 #include <jtag/jtag.h>
 
+#define JSP_BANNER "\n\r" \
+                  "******************************\n\r" \
+                  "**     JTAG Serial Port     **\n\r" \
+                  "******************************\n\r" \
+                  "\n\r"
+
+#define NO_OPTION                      0
+
 /* This an option to the adv debug unit.
  * If this is defined, status bits will be skipped on burst
  * reads and writes to improve download speeds.
  */
 #define ADBG_USE_HISPEED               1
 
+/* This an option to the adv debug unit.
+ * If this is defined, the JTAG Serial Port Server is started.
+ * This option must match the RTL configured option.
+ */
+#define ENABLE_JSP_SERVER              2
+
+/* Define this if you intend to use the JSP in a system with multiple
+ * devices on the JTAG chain
+ */
+#define ENABLE_JSP_MULTI               4
+
 /* Definitions for the top-level debug unit.  This really just consists
  * of a single register, used to select the active debug module ("chain").
  */
@@ -182,6 +202,17 @@ static int or1k_adv_jtag_init(struct or1k_jtag *jtag_info)
        if (or1k_du_adv.options & ADBG_USE_HISPEED)
                LOG_INFO("adv debug unit is configured with option ADBG_USE_HISPEED");
 
+       if (or1k_du_adv.options & ENABLE_JSP_SERVER) {
+               if (or1k_du_adv.options & ENABLE_JSP_MULTI)
+                       LOG_INFO("adv debug unit is configured with option ENABLE_JSP_MULTI");
+               LOG_INFO("adv debug unit is configured with option ENABLE_JSP_SERVER");
+               retval = jsp_init(jtag_info, JSP_BANNER);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Couldn't start the JSP server");
+                       return retval;
+               }
+       }
+
        LOG_DEBUG("Init done");
 
        return ERROR_OK;
@@ -962,9 +993,93 @@ static int or1k_adv_jtag_write_memory(struct or1k_jtag *jtag_info,
        return ERROR_OK;
 }
 
+int or1k_adv_jtag_jsp_xfer(struct or1k_jtag *jtag_info,
+                                 int *out_len, unsigned char *out_buffer,
+                                 int *in_len, unsigned char *in_buffer)
+{
+       LOG_DEBUG("JSP transfert");
+
+       int retval;
+       if (!jtag_info->or1k_jtag_inited)
+               return ERROR_OK;
+
+       retval = adbg_select_module(jtag_info, DC_JSP);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* return nb char xmit */
+       int xmitsize;
+       if (*out_len > 8)
+               xmitsize = 8;
+       else
+               xmitsize = *out_len;
+
+       uint8_t out_data[10];
+       uint8_t in_data[10];
+       struct scan_field field;
+       int startbit, stopbit, wrapbit;
+
+       memset(out_data, 0, 10);
+
+       if (or1k_du_adv.options & ENABLE_JSP_MULTI) {
+
+               startbit = 1;
+               wrapbit = (xmitsize >> 3) & 0x1;
+               out_data[0] = (xmitsize << 5) | 0x1;  /* set the start bit */
+
+               int i;
+               /* don't copy off the end of the input array */
+               for (i = 0; i < xmitsize; i++) {
+                       out_data[i + 1] = (out_buffer[i] << 1) | wrapbit;
+                       wrapbit = (out_buffer[i] >> 7) & 0x1;
+               }
+
+               if (i < 8)
+                       out_data[i + 1] = wrapbit;
+               else
+                       out_data[9] = wrapbit;
+
+               /* If the last data bit is a '1', then we need to append a '0' so the top-level module
+                * won't treat the burst as a 'module select' command.
+                */
+               stopbit = !!(out_data[9] & 0x01);
+
+       } else {
+               startbit = 0;
+               /* First byte out has write count in upper nibble */
+               out_data[0] = 0x0 | (xmitsize << 4);
+               if (xmitsize > 0)
+                       memcpy(&out_data[1], out_buffer, xmitsize);
+
+               /* If the last data bit is a '1', then we need to append a '0' so the top-level module
+                * won't treat the burst as a 'module select' command.
+                */
+               stopbit = !!(out_data[8] & 0x80);
+       }
+
+       field.num_bits = 72 + startbit + stopbit;
+       field.out_value = out_data;
+       field.in_value = in_data;
+
+       jtag_add_dr_scan(jtag_info->tap, 1, &field, TAP_IDLE);
+
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* bytes available is in the upper nibble */
+       *in_len = (in_data[0] >> 4) & 0xF;
+       memcpy(in_buffer, &in_data[1], *in_len);
+
+       int bytes_free = in_data[0] & 0x0F;
+       *out_len = (bytes_free < xmitsize) ? bytes_free : xmitsize;
+
+       return ERROR_OK;
+}
+
 static struct or1k_du or1k_du_adv = {
        .name                     = "adv",
-       .options                  = ADBG_USE_HISPEED,
+       .options                  = NO_OPTION,
        .or1k_jtag_init           = or1k_adv_jtag_init,
 
        .or1k_is_cpu_running      = or1k_adv_is_cpu_running,
index 5d23641a9cb7079687b40bf9b8469fc675668ffb..c543ebe25e02c21181139a2cf0944fc5899cdf94 100644 (file)
@@ -13,6 +13,9 @@ set CHIPNAME or1200
 
 source [find target/or1k.cfg]
 
+# Set the servers polling period to 1ms (needed to JSP Server)
+poll_period 1
+
 # Set the adapter speed
 adapter_khz 3000
 
index acec70026e84ce3c06d46242381a516d3f0a6fdb..360a0ddf3d80c5f3f4e9e007014a1c084cec769c 100644 (file)
@@ -61,10 +61,12 @@ if { [string compare $_TAP_TYPE "VJTAG"] == 0 } {
 
 # Select the debug unit core we are using. This debug unit as an option.
 
-proc ADBG_USE_HISPEED {}       { return 1 }
+set ADBG_USE_HISPEED           1
+set ENABLE_JSP_SERVER          2
+set ENABLE_JSP_MULTI           4
 
 # If ADBG_USE_HISPEED is set (options bit 1), status bits will be skipped
 # on burst reads and writes to improve download speeds.
 # This option must match the RTL configured option.
 
-du_select adv [ADBG_USE_HISPEED]
+du_select adv [expr $ADBG_USE_HISPEED | $ENABLE_JSP_SERVER | $ENABLE_JSP_MULTI]

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)