This is an automated email from Gerrit. Franck Jullien (franck.jull...@gmail.com) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/2162
-- gerrit commit 7749a6f2f45752e7296354589772d660f282d1a8 Author: Franck Jullien <franck.jull...@gmail.com> Date: Fri May 30 16:49:42 2014 +0200 openrisc: add support for JTAG Serial Port Change-Id: I623a8c74bcca2edb5f996b69c02d73a6f67b7d34 Signed-off-by: Franck Jullien <franck.jull...@gmail.com> diff --git a/src/server/server.c b/src/server/server.c index 5169319..d635706 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -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" @@ -380,8 +381,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 1ms */ + tv.tv_usec = 1000; /* Only while we're sleeping we'll let others run */ openocd_sleep_prelude(); kept_alive(); @@ -609,6 +610,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); } diff --git a/src/target/openrisc/Makefile.am b/src/target/openrisc/Makefile.am index f1e7eaa..b00a30d 100644 --- a/src/target/openrisc/Makefile.am +++ b/src/target/openrisc/Makefile.am @@ -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 index 0000000..597bfcb --- /dev/null +++ b/src/target/openrisc/jsp_server.c @@ -0,0 +1,247 @@ +/*************************************************************************** + * Copyright (C) 2014 by Franck Jullien * + * franck.jull...@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 index 0000000..3e7c114 --- /dev/null +++ b/src/target/openrisc/jsp_server.h @@ -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_ */ diff --git a/src/target/openrisc/or1k_du.h b/src/target/openrisc/or1k_du.h index 564241d..f5ee364 100644 --- a/src/target/openrisc/or1k_du.h +++ b/src/target/openrisc/or1k_du.h @@ -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 diff --git a/src/target/openrisc/or1k_du_adv.c b/src/target/openrisc/or1k_du_adv.c index f497a86..d1c1293 100644 --- a/src/target/openrisc/or1k_du_adv.c +++ b/src/target/openrisc/or1k_du_adv.c @@ -1,8 +1,8 @@ /*************************************************************************** - * Copyright (C) 2013 by Franck Jullien * + * Copyright (C) 2013-2014 by Franck Jullien * * elec4...@gmail.com * * * - * Inspired from adv_jtag_bridge which is: * + * Inspired from adv_jtag_bridge which is: * * Copyright (C) 2008-2010 Nathan Yawn * * ny...@opencores.net * * * @@ -33,10 +33,19 @@ #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. @@ -44,6 +53,17 @@ */ #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"). */ @@ -181,6 +201,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; @@ -953,9 +984,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, diff --git a/tcl/target/or1k.cfg b/tcl/target/or1k.cfg index acec700..360a0dd 100644 --- a/tcl/target/or1k.cfg +++ b/tcl/target/or1k.cfg @@ -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] -- ------------------------------------------------------------------------------ Learn Graph Databases - Download FREE O'Reilly Book "Graph Databases" is the definitive new guide to graph databases and their applications. Written by three acclaimed leaders in the field, this first edition is now available. Download your free book today! http://p.sf.net/sfu/NeoTech _______________________________________________ OpenOCD-devel mailing list OpenOCD-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openocd-devel