Browse Source

openrisc: add support for JTAG Serial Port

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>
tags/v0.9.0-rc1
Franck Jullien 9 years ago
committed by Andreas Fritiofson
parent
commit
712165f483
8 changed files with 426 additions and 9 deletions
  1. +29
    -2
      src/server/server.c
  2. +4
    -2
      src/target/openrisc/Makefile.am
  3. +247
    -0
      src/target/openrisc/jsp_server.c
  4. +17
    -0
      src/target/openrisc/jsp_server.h
  5. +4
    -0
      src/target/openrisc/or1k_du.h
  6. +118
    -3
      src/target/openrisc/or1k_du_adv.c
  7. +3
    -0
      tcl/board/or1k_generic.cfg
  8. +4
    -2
      tcl/target/or1k.cfg

+ 29
- 2
src/server/server.c View 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);
}



+ 4
- 2
src/target/openrisc/Makefile.am View 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

+ 247
- 0
src/target/openrisc/jsp_server.c View File

@@ -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);
}


+ 17
- 0
src/target/openrisc/jsp_server.h View File

@@ -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_ */

+ 4
- 0
src/target/openrisc/or1k_du.h View 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


+ 118
- 3
src/target/openrisc/or1k_du_adv.c View 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 *
* *
@@ -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").
*/
@@ -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,


+ 3
- 0
tcl/board/or1k_generic.cfg View 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



+ 4
- 2
tcl/target/or1k.cfg View 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]

Loading…
Cancel
Save