2008-09-27 13:00:01 +00:00
|
|
|
/***************************************************************************
|
2009-12-01 07:42:53 +00:00
|
|
|
* Copyright (C) 2007-2009 by Øyvind Harboe *
|
2008-09-27 13:00:01 +00:00
|
|
|
* *
|
|
|
|
* 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., *
|
|
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
|
|
***************************************************************************/
|
2009-12-08 09:40:47 +00:00
|
|
|
|
|
|
|
/* This file supports the zy1000 debugger: http://www.zylin.com/zy1000.html
|
|
|
|
*
|
|
|
|
* The zy1000 is a standalone debugger that has a web interface and
|
|
|
|
* requires no drivers on the developer host as all communication
|
|
|
|
* is via TCP/IP. The zy1000 gets it performance(~400-700kBytes/s
|
|
|
|
* DCC downloads @ 16MHz target) as it has an FPGA to hardware
|
|
|
|
* accelerate the JTAG commands, while offering *very* low latency
|
|
|
|
* between OpenOCD and the FPGA registers.
|
|
|
|
*
|
|
|
|
* The disadvantage of the zy1000 is that it has a feeble CPU compared to
|
|
|
|
* a PC(ca. 50-500 DMIPS depending on how one counts it), whereas a PC
|
|
|
|
* is on the order of 10000 DMIPS(i.e. at a factor of 20-200).
|
|
|
|
*
|
|
|
|
* The zy1000 revc hardware is using an Altera Nios CPU, whereas the
|
|
|
|
* revb is using ARM7 + Xilinx.
|
|
|
|
*
|
|
|
|
* See Zylin web pages or contact Zylin for more information.
|
|
|
|
*
|
|
|
|
* The reason this code is in OpenOCD rather than OpenOCD linked with the
|
|
|
|
* ZY1000 code is that OpenOCD is the long road towards getting
|
|
|
|
* libopenocd into place. libopenocd will support both low performance,
|
|
|
|
* low latency systems(embedded) and high performance high latency
|
|
|
|
* systems(PCs).
|
|
|
|
*/
|
2008-09-27 13:00:01 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2009-12-03 12:14:45 +00:00
|
|
|
#include <target/embeddedice.h>
|
2009-12-03 12:14:32 +00:00
|
|
|
#include <jtag/minidriver.h>
|
2009-12-03 12:14:31 +00:00
|
|
|
#include <jtag/interface.h>
|
2009-10-19 13:08:52 +00:00
|
|
|
#include "zy1000_version.h"
|
2008-09-27 13:00:01 +00:00
|
|
|
|
|
|
|
#include <cyg/hal/hal_io.h> // low level i/o
|
|
|
|
#include <cyg/hal/hal_diag.h>
|
|
|
|
|
2009-11-13 12:54:20 +00:00
|
|
|
#include <time.h>
|
|
|
|
|
2009-12-25 20:50:41 +00:00
|
|
|
#ifdef CYGPKG_HAL_NIOS2
|
|
|
|
#include <cyg/hal/io.h>
|
|
|
|
#include <cyg/firmwareutil/firmwareutil.h>
|
|
|
|
#endif
|
|
|
|
|
2009-10-19 13:08:52 +00:00
|
|
|
#define ZYLIN_VERSION GIT_ZY1000_VERSION
|
2008-12-15 11:32:22 +00:00
|
|
|
#define ZYLIN_DATE __DATE__
|
|
|
|
#define ZYLIN_TIME __TIME__
|
2009-10-19 13:08:52 +00:00
|
|
|
#define ZYLIN_OPENOCD GIT_OPENOCD_VERSION
|
2009-10-20 07:46:23 +00:00
|
|
|
#define ZYLIN_OPENOCD_VERSION "ZY1000 " ZYLIN_VERSION " " ZYLIN_DATE
|
2008-09-27 13:00:01 +00:00
|
|
|
|
|
|
|
|
2008-11-05 07:45:31 +00:00
|
|
|
static int zy1000_khz(int khz, int *jtag_speed)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:42:03 +00:00
|
|
|
if (khz == 0)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
*jtag_speed = 0;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
*jtag_speed = 64000/khz;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2008-11-05 07:45:31 +00:00
|
|
|
static int zy1000_speed_div(int speed, int *khz)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:42:03 +00:00
|
|
|
if (speed == 0)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
*khz = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
*khz = 64000/speed;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2009-01-09 10:12:43 +00:00
|
|
|
static bool readPowerDropout(void)
|
2008-11-05 07:45:31 +00:00
|
|
|
{
|
|
|
|
cyg_uint32 state;
|
|
|
|
// sample and clear power dropout
|
2009-12-07 11:38:56 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x80);
|
|
|
|
ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, state);
|
2008-11-05 07:45:31 +00:00
|
|
|
bool powerDropout;
|
|
|
|
powerDropout = (state & 0x80) != 0;
|
|
|
|
return powerDropout;
|
|
|
|
}
|
2008-09-27 13:00:01 +00:00
|
|
|
|
2008-11-05 07:45:31 +00:00
|
|
|
|
2009-01-09 10:12:43 +00:00
|
|
|
static bool readSRST(void)
|
2008-11-05 07:45:31 +00:00
|
|
|
{
|
|
|
|
cyg_uint32 state;
|
|
|
|
// sample and clear SRST sensing
|
2009-12-07 11:38:56 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000040);
|
|
|
|
ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, state);
|
2008-11-05 07:45:31 +00:00
|
|
|
bool srstAsserted;
|
|
|
|
srstAsserted = (state & 0x40) != 0;
|
|
|
|
return srstAsserted;
|
|
|
|
}
|
|
|
|
|
2008-11-11 12:09:35 +00:00
|
|
|
static int zy1000_srst_asserted(int *srst_asserted)
|
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
*srst_asserted = readSRST();
|
2008-11-11 12:09:35 +00:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2008-11-05 07:45:31 +00:00
|
|
|
static int zy1000_power_dropout(int *dropout)
|
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
*dropout = readPowerDropout();
|
2008-11-05 07:45:31 +00:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void zy1000_reset(int trst, int srst)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
LOG_DEBUG("zy1000 trst=%d, srst=%d", trst, srst);
|
2010-01-11 09:21:56 +00:00
|
|
|
|
|
|
|
/* flush the JTAG FIFO. Not flushing the queue before messing with
|
|
|
|
* reset has such interesting bugs as causing hard to reproduce
|
|
|
|
* RCLK bugs as RCLK will stop responding when TRST is asserted
|
|
|
|
*/
|
|
|
|
waitIdle();
|
|
|
|
|
2009-06-23 22:35:09 +00:00
|
|
|
if (!srst)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x00000001);
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-06-23 22:38:12 +00:00
|
|
|
/* Danger!!! if clk != 0 when in
|
2008-12-13 06:25:50 +00:00
|
|
|
* idle in TAP_IDLE, reset halt on str912 will fail.
|
2008-09-27 13:00:01 +00:00
|
|
|
*/
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000001);
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
2009-06-23 22:35:09 +00:00
|
|
|
if (!trst)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x00000002);
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* assert reset */
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000002);
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
2008-11-05 07:45:31 +00:00
|
|
|
|
2009-06-23 22:39:47 +00:00
|
|
|
if (trst||(srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2008-12-13 06:59:24 +00:00
|
|
|
/* we're now in the RESET state until trst is deasserted */
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_RESET);
|
2008-09-27 13:00:01 +00:00
|
|
|
} else
|
|
|
|
{
|
|
|
|
/* We'll get RCLK failure when we assert TRST, so clear any false positives here */
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x400);
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* wait for srst to float back up */
|
|
|
|
if (!srst)
|
|
|
|
{
|
|
|
|
int i;
|
2009-06-23 22:45:47 +00:00
|
|
|
for (i = 0; i < 1000; i++)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
// We don't want to sense our own reset, so we clear here.
|
|
|
|
// There is of course a timing hole where we could loose
|
|
|
|
// a "real" reset.
|
|
|
|
if (!readSRST())
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* wait 1ms */
|
|
|
|
alive_sleep(1);
|
|
|
|
}
|
|
|
|
|
2009-06-23 22:42:03 +00:00
|
|
|
if (i == 1000)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
LOG_USER("SRST didn't deassert after %dms", i);
|
2009-06-23 22:45:47 +00:00
|
|
|
} else if (i > 1)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
LOG_USER("SRST took %dms to deassert", i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-05 07:45:31 +00:00
|
|
|
int zy1000_speed(int speed)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2010-01-18 20:54:58 +00:00
|
|
|
/* flush JTAG master FIFO before setting speed */
|
|
|
|
waitIdle();
|
|
|
|
|
2009-06-23 22:35:09 +00:00
|
|
|
if (speed == 0)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
/*0 means RCLK*/
|
|
|
|
speed = 0;
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x100);
|
2008-09-27 13:00:01 +00:00
|
|
|
LOG_DEBUG("jtag_speed using RCLK");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-06-23 22:35:09 +00:00
|
|
|
if (speed > 8190 || speed < 2)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2008-12-15 11:32:22 +00:00
|
|
|
LOG_USER("valid ZY1000 jtag_speed=[8190,2]. Divisor is 64MHz / even values between 8190-2, i.e. min 7814Hz, max 32MHz");
|
2008-09-27 13:00:01 +00:00
|
|
|
return ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_USER("jtag_speed %d => JTAG clk=%f", speed, 64.0/(float)speed);
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x100);
|
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x1c, speed&~1);
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2008-12-15 11:32:22 +00:00
|
|
|
static bool savePower;
|
2008-09-27 13:00:01 +00:00
|
|
|
|
|
|
|
|
2008-12-15 11:32:22 +00:00
|
|
|
static void setPower(bool power)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2008-12-15 11:32:22 +00:00
|
|
|
savePower = power;
|
|
|
|
if (power)
|
|
|
|
{
|
2009-12-07 11:38:56 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x8);
|
2008-12-15 11:32:22 +00:00
|
|
|
} else
|
|
|
|
{
|
2009-12-07 11:38:56 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x8);
|
2008-12-15 11:32:22 +00:00
|
|
|
}
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
2009-11-18 14:00:26 +00:00
|
|
|
COMMAND_HANDLER(handle_power_command)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-11-18 14:00:26 +00:00
|
|
|
switch (CMD_ARGC)
|
2008-12-15 11:32:22 +00:00
|
|
|
{
|
2009-11-18 14:00:26 +00:00
|
|
|
case 1: {
|
2009-11-18 13:22:44 +00:00
|
|
|
bool enable;
|
2009-11-18 14:00:26 +00:00
|
|
|
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable);
|
2009-11-18 13:22:44 +00:00
|
|
|
setPower(enable);
|
2009-11-18 14:00:26 +00:00
|
|
|
// fall through
|
|
|
|
}
|
|
|
|
case 0:
|
2009-11-22 12:16:48 +00:00
|
|
|
LOG_INFO("Target power %s", savePower ? "on" : "off");
|
2009-11-18 14:00:26 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return ERROR_INVALID_ARGUMENTS;
|
2008-12-15 11:32:22 +00:00
|
|
|
}
|
2008-09-27 13:00:01 +00:00
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-15 11:32:22 +00:00
|
|
|
/* Give TELNET a way to find out what version this is */
|
2009-05-06 11:22:30 +00:00
|
|
|
static int jim_zy1000_version(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-11-13 12:54:20 +00:00
|
|
|
if ((argc < 1) || (argc > 3))
|
2009-05-06 11:22:30 +00:00
|
|
|
return JIM_ERR;
|
2009-06-23 22:42:54 +00:00
|
|
|
const char *version_str = NULL;
|
2009-05-06 11:22:30 +00:00
|
|
|
|
|
|
|
if (argc == 1)
|
2008-12-14 20:33:01 +00:00
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
version_str = ZYLIN_OPENOCD_VERSION;
|
2009-05-06 11:22:30 +00:00
|
|
|
} else
|
2008-12-14 20:33:01 +00:00
|
|
|
{
|
2009-05-06 11:22:30 +00:00
|
|
|
const char *str = Jim_GetString(argv[1], NULL);
|
2009-11-13 12:54:20 +00:00
|
|
|
const char *str2 = NULL;
|
|
|
|
if (argc > 2)
|
|
|
|
str2 = Jim_GetString(argv[2], NULL);
|
2009-05-06 11:22:30 +00:00
|
|
|
if (strcmp("openocd", str) == 0)
|
|
|
|
{
|
2009-10-19 13:08:52 +00:00
|
|
|
version_str = ZYLIN_OPENOCD;
|
2009-05-06 11:22:30 +00:00
|
|
|
}
|
|
|
|
else if (strcmp("zy1000", str) == 0)
|
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
version_str = ZYLIN_VERSION;
|
2009-05-06 11:22:30 +00:00
|
|
|
}
|
|
|
|
else if (strcmp("date", str) == 0)
|
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
version_str = ZYLIN_DATE;
|
2009-05-06 11:22:30 +00:00
|
|
|
}
|
2009-10-20 07:46:23 +00:00
|
|
|
else if (strcmp("time", str) == 0)
|
|
|
|
{
|
|
|
|
version_str = ZYLIN_TIME;
|
|
|
|
}
|
2009-06-26 12:57:56 +00:00
|
|
|
else if (strcmp("pcb", str) == 0)
|
|
|
|
{
|
|
|
|
#ifdef CYGPKG_HAL_NIOS2
|
|
|
|
version_str="c";
|
|
|
|
#else
|
|
|
|
version_str="b";
|
|
|
|
#endif
|
|
|
|
}
|
2009-11-13 12:54:20 +00:00
|
|
|
#ifdef CYGPKG_HAL_NIOS2
|
|
|
|
else if (strcmp("fpga", str) == 0)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* return a list of 32 bit integers to describe the expected
|
|
|
|
* and actual FPGA
|
|
|
|
*/
|
|
|
|
static char *fpga_id = "0x12345678 0x12345678 0x12345678 0x12345678";
|
|
|
|
cyg_uint32 id, timestamp;
|
|
|
|
HAL_READ_UINT32(SYSID_BASE, id);
|
|
|
|
HAL_READ_UINT32(SYSID_BASE+4, timestamp);
|
|
|
|
sprintf(fpga_id, "0x%08x 0x%08x 0x%08x 0x%08x", id, timestamp, SYSID_ID, SYSID_TIMESTAMP);
|
|
|
|
version_str = fpga_id;
|
|
|
|
if ((argc>2) && (strcmp("time", str2) == 0))
|
|
|
|
{
|
|
|
|
time_t last_mod = timestamp;
|
|
|
|
char * t = ctime (&last_mod) ;
|
|
|
|
t[strlen(t)-1] = 0;
|
|
|
|
version_str = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-05-06 11:22:30 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
return JIM_ERR;
|
|
|
|
}
|
2008-12-14 20:33:01 +00:00
|
|
|
}
|
2008-09-27 13:00:01 +00:00
|
|
|
|
2009-05-06 11:22:30 +00:00
|
|
|
Jim_SetResult(interp, Jim_NewStringObj(interp, version_str, -1));
|
|
|
|
|
|
|
|
return JIM_OK;
|
2008-12-15 11:32:22 +00:00
|
|
|
}
|
|
|
|
|
2008-09-27 13:00:01 +00:00
|
|
|
|
2009-06-26 12:57:56 +00:00
|
|
|
#ifdef CYGPKG_HAL_NIOS2
|
2009-12-25 20:50:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
struct info_forward
|
|
|
|
{
|
|
|
|
void *data;
|
|
|
|
struct cyg_upgrade_info *upgraded_file;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void report_info(void *data, const char * format, va_list args)
|
|
|
|
{
|
|
|
|
char *s = alloc_vprintf(format, args);
|
|
|
|
LOG_USER_N("%s", s);
|
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct cyg_upgrade_info firmware_info =
|
|
|
|
{
|
|
|
|
(cyg_uint8 *)0x84000000,
|
|
|
|
"/ram/firmware.phi",
|
|
|
|
"Firmware",
|
|
|
|
0x0300000,
|
|
|
|
0x1f00000 -
|
|
|
|
0x0300000,
|
|
|
|
"ZylinNiosFirmware\n",
|
|
|
|
report_info,
|
|
|
|
};
|
|
|
|
|
2009-06-26 12:57:56 +00:00
|
|
|
static int jim_zy1000_writefirmware(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
|
|
|
{
|
|
|
|
if (argc != 2)
|
|
|
|
return JIM_ERR;
|
|
|
|
|
|
|
|
int length;
|
|
|
|
const char *str = Jim_GetString(argv[1], &length);
|
|
|
|
|
2009-12-25 20:50:41 +00:00
|
|
|
/* */
|
|
|
|
int tmpFile;
|
|
|
|
if ((tmpFile = open(firmware_info.file, O_RDWR | O_CREAT | O_TRUNC)) <= 0)
|
|
|
|
{
|
|
|
|
return JIM_ERR;
|
|
|
|
}
|
|
|
|
bool success;
|
|
|
|
success = write(tmpFile, str, length) == length;
|
|
|
|
close(tmpFile);
|
|
|
|
if (!success)
|
2009-06-26 12:57:56 +00:00
|
|
|
return JIM_ERR;
|
|
|
|
|
2009-12-25 20:50:41 +00:00
|
|
|
if (!cyg_firmware_upgrade(NULL, firmware_info))
|
|
|
|
return JIM_ERR;
|
2009-06-26 12:57:56 +00:00
|
|
|
|
2009-12-25 20:50:41 +00:00
|
|
|
return JIM_OK;
|
2009-06-26 12:57:56 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-12-17 14:07:03 +00:00
|
|
|
static int
|
|
|
|
zylinjtag_Jim_Command_powerstatus(Jim_Interp *interp,
|
2009-02-03 05:59:17 +00:00
|
|
|
int argc,
|
2008-12-17 14:07:03 +00:00
|
|
|
Jim_Obj * const *argv)
|
|
|
|
{
|
|
|
|
if (argc != 1)
|
|
|
|
{
|
|
|
|
Jim_WrongNumArgs(interp, 1, argv, "powerstatus");
|
|
|
|
return JIM_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
cyg_uint32 status;
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, status);
|
2008-12-17 14:07:03 +00:00
|
|
|
|
2009-06-23 22:38:12 +00:00
|
|
|
Jim_SetResult(interp, Jim_NewIntObj(interp, (status&0x80) != 0));
|
2008-12-17 14:07:03 +00:00
|
|
|
|
|
|
|
return JIM_OK;
|
|
|
|
}
|
|
|
|
|
2008-12-15 11:32:22 +00:00
|
|
|
|
2008-12-17 14:07:03 +00:00
|
|
|
|
|
|
|
|
2008-12-15 11:32:22 +00:00
|
|
|
int zy1000_init(void)
|
|
|
|
{
|
2008-12-17 14:55:12 +00:00
|
|
|
LOG_USER("%s", ZYLIN_OPENOCD_VERSION);
|
2008-12-15 11:32:22 +00:00
|
|
|
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x30); // Turn on LED1 & LED2
|
2008-12-15 11:32:22 +00:00
|
|
|
|
|
|
|
setPower(true); // on by default
|
|
|
|
|
|
|
|
|
|
|
|
/* deassert resets. Important to avoid infinite loop waiting for SRST to deassert */
|
|
|
|
zy1000_reset(0, 0);
|
2009-06-09 08:40:10 +00:00
|
|
|
zy1000_speed(jtag_get_speed());
|
2008-12-15 11:32:22 +00:00
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int zy1000_quit(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
return ERROR_OK;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int interface_jtag_execute_queue(void)
|
|
|
|
{
|
|
|
|
cyg_uint32 empty;
|
|
|
|
|
|
|
|
waitIdle();
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, empty);
|
2008-09-27 13:00:01 +00:00
|
|
|
/* clear JTAG error register */
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x400);
|
2008-09-27 13:00:01 +00:00
|
|
|
|
2009-06-23 22:38:12 +00:00
|
|
|
if ((empty&0x400) != 0)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
LOG_WARNING("RCLK timeout");
|
|
|
|
/* the error is informative only as we don't want to break the firmware if there
|
|
|
|
* is a false positive.
|
|
|
|
*/
|
|
|
|
// return ERROR_FAIL;
|
|
|
|
}
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-01-09 10:12:43 +00:00
|
|
|
static cyg_uint32 getShiftValue(void)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
cyg_uint32 value;
|
|
|
|
waitIdle();
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_PEEK(ZY1000_JTAG_BASE + 0xc, value);
|
2008-09-27 13:00:01 +00:00
|
|
|
VERBOSE(LOG_INFO("getShiftValue %08x", value));
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
#if 0
|
2009-01-09 10:12:43 +00:00
|
|
|
static cyg_uint32 getShiftValueFlip(void)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
cyg_uint32 value;
|
|
|
|
waitIdle();
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_PEEK(ZY1000_JTAG_BASE + 0x18, value);
|
2008-09-27 13:00:01 +00:00
|
|
|
VERBOSE(LOG_INFO("getShiftValue %08x (flipped)", value));
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if 0
|
2009-02-03 05:59:17 +00:00
|
|
|
static void shiftValueInnerFlip(const tap_state_t state, const tap_state_t endState, int repeat, cyg_uint32 value)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-02-03 05:59:17 +00:00
|
|
|
VERBOSE(LOG_INFO("shiftValueInner %s %s %d %08x (flipped)", tap_state_name(state), tap_state_name(endState), repeat, value));
|
2008-09-27 13:00:01 +00:00
|
|
|
cyg_uint32 a,b;
|
2009-06-23 22:42:54 +00:00
|
|
|
a = state;
|
|
|
|
b = endState;
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0xc, value);
|
2009-06-23 22:45:15 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x8, (1 << 15) | (repeat << 8) | (a << 4) | b);
|
2008-09-27 13:00:01 +00:00
|
|
|
VERBOSE(getShiftValueFlip());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-07-06 12:03:55 +00:00
|
|
|
static void gotoEndState(tap_state_t end_state)
|
|
|
|
{
|
|
|
|
setCurrentState(end_state);
|
|
|
|
}
|
|
|
|
|
2009-11-13 11:28:03 +00:00
|
|
|
static __inline void scanFields(int num_fields, const struct scan_field *fields, tap_state_t shiftState, int pause)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int j;
|
|
|
|
int k;
|
|
|
|
|
|
|
|
for (i = 0; i < num_fields; i++)
|
|
|
|
{
|
|
|
|
cyg_uint32 value;
|
|
|
|
|
2009-06-23 22:42:54 +00:00
|
|
|
uint8_t *inBuffer = NULL;
|
2008-09-27 13:00:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
// figure out where to store the input data
|
2009-06-23 22:42:54 +00:00
|
|
|
int num_bits = fields[i].num_bits;
|
2009-06-23 22:38:12 +00:00
|
|
|
if (fields[i].in_value != NULL)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
inBuffer = fields[i].in_value;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// here we shuffle N bits out/in
|
2009-06-23 22:42:54 +00:00
|
|
|
j = 0;
|
2009-06-23 22:45:47 +00:00
|
|
|
while (j < num_bits)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-02-03 05:59:17 +00:00
|
|
|
tap_state_t pause_state;
|
2008-09-27 13:00:01 +00:00
|
|
|
int l;
|
2009-06-23 22:42:54 +00:00
|
|
|
k = num_bits-j;
|
|
|
|
pause_state = (shiftState == TAP_DRSHIFT)?TAP_DRSHIFT:TAP_IRSHIFT;
|
2009-06-23 22:45:47 +00:00
|
|
|
if (k > 32)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
k = 32;
|
2008-09-27 13:00:01 +00:00
|
|
|
/* we have more to shift out */
|
2009-07-06 12:03:55 +00:00
|
|
|
} else if (pause&&(i == num_fields-1))
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
/* this was the last to shift out this time */
|
2009-07-06 12:03:55 +00:00
|
|
|
pause_state = (shiftState==TAP_DRSHIFT)?TAP_DRPAUSE:TAP_IRPAUSE;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
2009-06-23 22:44:17 +00:00
|
|
|
// we have (num_bits + 7)/8 bytes of bits to toggle out.
|
2008-09-27 13:00:01 +00:00
|
|
|
// bits are pushed out LSB to MSB
|
2009-06-23 22:42:54 +00:00
|
|
|
value = 0;
|
2009-06-23 22:38:12 +00:00
|
|
|
if (fields[i].out_value != NULL)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:45:47 +00:00
|
|
|
for (l = 0; l < k; l += 8)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:44:17 +00:00
|
|
|
value|=fields[i].out_value[(j + l)/8]<<l;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* mask away unused bits for easier debugging */
|
2009-11-12 09:10:11 +00:00
|
|
|
if (k < 32)
|
|
|
|
{
|
|
|
|
value&=~(((uint32_t)0xffffffff) << k);
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
/* Shifting by >= 32 is not defined by the C standard
|
|
|
|
* and will in fact shift by &0x1f bits on nios */
|
|
|
|
}
|
2008-09-27 13:00:01 +00:00
|
|
|
|
|
|
|
shiftValueInner(shiftState, pause_state, k, value);
|
|
|
|
|
2009-06-23 22:38:12 +00:00
|
|
|
if (inBuffer != NULL)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
// data in, LSB to MSB
|
2009-06-23 22:42:54 +00:00
|
|
|
value = getShiftValue();
|
2008-09-27 13:00:01 +00:00
|
|
|
// we're shifting in data to MSB, shift data to be aligned for returning the value
|
|
|
|
value >>= 32-k;
|
|
|
|
|
2009-06-23 22:45:47 +00:00
|
|
|
for (l = 0; l < k; l += 8)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:44:17 +00:00
|
|
|
inBuffer[(j + l)/8]=(value >> l)&0xff;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
}
|
2009-06-23 22:39:18 +00:00
|
|
|
j += k;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-13 11:28:03 +00:00
|
|
|
int interface_jtag_add_ir_scan(int num_fields, const struct scan_field *fields, tap_state_t state)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
|
2008-12-01 14:21:24 +00:00
|
|
|
int j;
|
2008-09-27 13:00:01 +00:00
|
|
|
int scan_size = 0;
|
2009-11-13 11:19:35 +00:00
|
|
|
struct jtag_tap *tap, *nextTap;
|
2009-06-23 22:42:54 +00:00
|
|
|
for (tap = jtag_tap_next_enabled(NULL); tap!= NULL; tap = nextTap)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
nextTap = jtag_tap_next_enabled(tap);
|
2009-07-06 12:03:55 +00:00
|
|
|
int pause = (nextTap==NULL);
|
2008-12-01 14:21:24 +00:00
|
|
|
|
2008-09-27 13:00:01 +00:00
|
|
|
int found = 0;
|
2008-11-19 08:22:47 +00:00
|
|
|
|
2008-12-01 14:21:24 +00:00
|
|
|
scan_size = tap->ir_length;
|
2008-09-27 13:00:01 +00:00
|
|
|
|
|
|
|
/* search the list */
|
2009-06-23 22:42:54 +00:00
|
|
|
for (j = 0; j < num_fields; j++)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2008-12-01 14:21:24 +00:00
|
|
|
if (tap == fields[j].tap)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
found = 1;
|
|
|
|
|
2009-07-06 12:03:55 +00:00
|
|
|
scanFields(1, fields + j, TAP_IRSHIFT, pause);
|
2008-09-27 13:00:01 +00:00
|
|
|
/* update device information */
|
2008-12-01 14:21:24 +00:00
|
|
|
buf_cpy(fields[j].out_value, tap->cur_instr, scan_size);
|
2008-09-27 13:00:01 +00:00
|
|
|
|
2008-12-01 14:21:24 +00:00
|
|
|
tap->bypass = 0;
|
2008-09-27 13:00:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
/* if a device isn't listed, set it to BYPASS */
|
2009-06-18 07:07:12 +00:00
|
|
|
uint8_t ones[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
|
2008-09-27 13:00:01 +00:00
|
|
|
|
2009-11-13 11:28:03 +00:00
|
|
|
struct scan_field tmp;
|
2008-09-27 13:00:01 +00:00
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
|
|
tmp.out_value = ones;
|
|
|
|
tmp.num_bits = scan_size;
|
2009-07-06 12:03:55 +00:00
|
|
|
scanFields(1, &tmp, TAP_IRSHIFT, pause);
|
2008-09-27 13:00:01 +00:00
|
|
|
/* update device information */
|
2008-12-01 14:21:24 +00:00
|
|
|
buf_cpy(tmp.out_value, tap->cur_instr, scan_size);
|
|
|
|
tap->bypass = 1;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
}
|
2009-07-06 12:03:55 +00:00
|
|
|
gotoEndState(state);
|
2008-09-27 13:00:01 +00:00
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-11-13 11:28:03 +00:00
|
|
|
int interface_jtag_add_plain_ir_scan(int num_fields, const struct scan_field *fields, tap_state_t state)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-07-06 12:03:55 +00:00
|
|
|
scanFields(num_fields, fields, TAP_IRSHIFT, 1);
|
|
|
|
gotoEndState(state);
|
2008-09-27 13:00:01 +00:00
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2009-11-13 11:28:03 +00:00
|
|
|
int interface_jtag_add_dr_scan(int num_fields, const struct scan_field *fields, tap_state_t state)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2008-12-01 14:21:24 +00:00
|
|
|
|
|
|
|
int j;
|
2009-11-13 11:19:35 +00:00
|
|
|
struct jtag_tap *tap, *nextTap;
|
2009-06-23 22:42:54 +00:00
|
|
|
for (tap = jtag_tap_next_enabled(NULL); tap!= NULL; tap = nextTap)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
nextTap = jtag_tap_next_enabled(tap);
|
|
|
|
int found = 0;
|
2009-07-06 12:03:55 +00:00
|
|
|
int pause = (nextTap==NULL);
|
2008-09-27 13:00:01 +00:00
|
|
|
|
2009-06-23 22:42:54 +00:00
|
|
|
for (j = 0; j < num_fields; j++)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2010-02-08 14:40:53 +00:00
|
|
|
/* Find a range of fields to write to this tap */
|
2008-12-01 14:21:24 +00:00
|
|
|
if (tap == fields[j].tap)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
found = 1;
|
2010-02-08 14:40:53 +00:00
|
|
|
int i;
|
|
|
|
for (i = j + 1; i < num_fields; i++)
|
|
|
|
{
|
|
|
|
if (tap != fields[j].tap)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
scanFields(i - j, fields + j, TAP_DRSHIFT, pause);
|
2008-09-27 13:00:01 +00:00
|
|
|
|
2010-02-08 14:40:53 +00:00
|
|
|
j = i;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
}
|
2010-02-08 14:40:53 +00:00
|
|
|
|
2008-09-27 13:00:01 +00:00
|
|
|
if (!found)
|
|
|
|
{
|
2010-02-08 14:40:53 +00:00
|
|
|
/* Shift out a 0 for disabled tap's */
|
|
|
|
shiftValueInner(TAP_DRSHIFT, pause?TAP_DRPAUSE:TAP_DRSHIFT, 1, 0);
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
2009-07-06 12:03:55 +00:00
|
|
|
gotoEndState(state);
|
2008-09-27 13:00:01 +00:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2009-11-13 11:28:03 +00:00
|
|
|
int interface_jtag_add_plain_dr_scan(int num_fields, const struct scan_field *fields, tap_state_t state)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-07-06 12:03:55 +00:00
|
|
|
scanFields(num_fields, fields, TAP_DRSHIFT, 1);
|
|
|
|
gotoEndState(state);
|
2008-09-27 13:00:01 +00:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int interface_jtag_add_tlr()
|
|
|
|
{
|
2008-12-13 06:25:50 +00:00
|
|
|
setCurrentState(TAP_RESET);
|
2008-09-27 13:00:01 +00:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int interface_jtag_add_reset(int req_trst, int req_srst)
|
|
|
|
{
|
2008-11-05 07:45:31 +00:00
|
|
|
zy1000_reset(req_trst, req_srst);
|
2008-09-27 13:00:01 +00:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-03 05:59:17 +00:00
|
|
|
static int zy1000_jtag_add_clocks(int num_cycles, tap_state_t state, tap_state_t clockstate)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
/* num_cycles can be 0 */
|
2009-01-09 10:12:43 +00:00
|
|
|
setCurrentState(clockstate);
|
2008-09-27 13:00:01 +00:00
|
|
|
|
|
|
|
/* execute num_cycles, 32 at the time. */
|
|
|
|
int i;
|
2009-06-23 22:45:47 +00:00
|
|
|
for (i = 0; i < num_cycles; i += 32)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
int num;
|
2009-06-23 22:42:54 +00:00
|
|
|
num = 32;
|
2009-06-23 22:45:47 +00:00
|
|
|
if (num_cycles-i < num)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
num = num_cycles-i;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
2009-01-09 10:12:43 +00:00
|
|
|
shiftValueInner(clockstate, clockstate, num, 0);
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if !TEST_MANUAL()
|
|
|
|
/* finish in end_state */
|
|
|
|
setCurrentState(state);
|
|
|
|
#else
|
2009-06-23 22:42:54 +00:00
|
|
|
tap_state_t t = TAP_IDLE;
|
2008-09-27 13:00:01 +00:00
|
|
|
/* test manual drive code on any target */
|
|
|
|
int tms;
|
2009-06-18 07:07:12 +00:00
|
|
|
uint8_t tms_scan = tap_get_tms_path(t, state);
|
2009-05-18 20:25:19 +00:00
|
|
|
int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state());
|
2008-11-05 07:45:31 +00:00
|
|
|
|
2009-05-18 20:25:19 +00:00
|
|
|
for (i = 0; i < tms_count; i++)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
tms = (tms_scan >> i) & 1;
|
|
|
|
waitIdle();
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, tms);
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
waitIdle();
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, state);
|
2008-09-27 13:00:01 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2009-02-03 05:59:17 +00:00
|
|
|
int interface_jtag_add_runtest(int num_cycles, tap_state_t state)
|
2009-01-09 10:12:43 +00:00
|
|
|
{
|
|
|
|
return zy1000_jtag_add_clocks(num_cycles, state, TAP_IDLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
int interface_jtag_add_clocks(int num_cycles)
|
|
|
|
{
|
2009-06-04 12:52:54 +00:00
|
|
|
return zy1000_jtag_add_clocks(num_cycles, cmd_queue_cur_state, cmd_queue_cur_state);
|
2009-01-09 10:12:43 +00:00
|
|
|
}
|
|
|
|
|
2009-06-18 07:11:11 +00:00
|
|
|
int interface_jtag_add_sleep(uint32_t us)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
jtag_sleep(us);
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2009-06-02 10:09:53 +00:00
|
|
|
int interface_jtag_add_pathmove(int num_states, const tap_state_t *path)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
int state_count;
|
|
|
|
int tms = 0;
|
|
|
|
|
|
|
|
/*wait for the fifo to be empty*/
|
|
|
|
waitIdle();
|
|
|
|
|
|
|
|
state_count = 0;
|
|
|
|
|
2009-06-23 22:42:54 +00:00
|
|
|
tap_state_t cur_state = cmd_queue_cur_state;
|
2008-09-27 13:00:01 +00:00
|
|
|
|
|
|
|
while (num_states)
|
|
|
|
{
|
2009-02-10 18:21:17 +00:00
|
|
|
if (tap_state_transition(cur_state, false) == path[state_count])
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
tms = 0;
|
|
|
|
}
|
2009-02-10 18:21:17 +00:00
|
|
|
else if (tap_state_transition(cur_state, true) == path[state_count])
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
tms = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-02-03 05:59:17 +00:00
|
|
|
LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(cur_state), tap_state_name(path[state_count]));
|
2008-09-27 13:00:01 +00:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
waitIdle();
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, tms);
|
2008-09-27 13:00:01 +00:00
|
|
|
|
|
|
|
cur_state = path[state_count];
|
|
|
|
state_count++;
|
|
|
|
num_states--;
|
|
|
|
}
|
|
|
|
|
|
|
|
waitIdle();
|
2009-06-23 22:44:17 +00:00
|
|
|
ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, cur_state);
|
2008-09-27 13:00:01 +00:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-11-13 11:19:35 +00:00
|
|
|
void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, uint8_t *buffer, int little, int count)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
2009-06-23 22:42:54 +00:00
|
|
|
// static int const reg_addr = 0x5;
|
|
|
|
tap_state_t end_state = jtag_get_end_state();
|
2009-06-23 22:42:03 +00:00
|
|
|
if (jtag_tap_next_enabled(jtag_tap_next_enabled(NULL)) == NULL)
|
2008-09-27 13:00:01 +00:00
|
|
|
{
|
|
|
|
/* better performance via code duplication */
|
|
|
|
if (little)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2008-12-13 06:25:50 +00:00
|
|
|
shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, fast_target_buffer_get_u32(buffer, 1));
|
2009-06-23 22:45:15 +00:00
|
|
|
shiftValueInner(TAP_DRSHIFT, end_state, 6, reg_addr | (1 << 5));
|
2009-06-23 22:39:18 +00:00
|
|
|
buffer += 4;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2008-12-13 06:25:50 +00:00
|
|
|
shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, fast_target_buffer_get_u32(buffer, 0));
|
2009-06-23 22:45:15 +00:00
|
|
|
shiftValueInner(TAP_DRSHIFT, end_state, 6, reg_addr | (1 << 5));
|
2009-06-23 22:39:18 +00:00
|
|
|
buffer += 4;
|
2008-09-27 13:00:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2008-12-01 14:21:24 +00:00
|
|
|
embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, little));
|
2008-09-27 13:00:01 +00:00
|
|
|
buffer += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-09 10:12:43 +00:00
|
|
|
|
2009-11-27 19:41:06 +00:00
|
|
|
static const struct command_registration zy1000_commands[] = {
|
|
|
|
{
|
|
|
|
.name = "power",
|
2010-01-10 06:14:08 +00:00
|
|
|
.handler = handle_power_command,
|
2009-11-27 19:41:06 +00:00
|
|
|
.mode = COMMAND_ANY,
|
2010-01-10 06:14:08 +00:00
|
|
|
.help = "Turn power switch to target on/off. "
|
|
|
|
"With no arguments, prints status.",
|
|
|
|
.usage = "('on'|'off)",
|
2009-11-27 19:41:06 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "zy1000_version",
|
|
|
|
.mode = COMMAND_ANY,
|
2010-01-10 06:14:08 +00:00
|
|
|
.jim_handler = jim_zy1000_version,
|
|
|
|
.help = "Print version info for zy1000.",
|
|
|
|
.usage = "['openocd'|'zy1000'|'date'|'time'|'pcb'|'fpga']",
|
2009-11-27 19:41:06 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "powerstatus",
|
|
|
|
.mode = COMMAND_ANY,
|
2010-01-10 06:14:08 +00:00
|
|
|
.jim_handler = zylinjtag_Jim_Command_powerstatus,
|
|
|
|
.help = "Returns power status of target",
|
2009-11-27 19:41:06 +00:00
|
|
|
},
|
|
|
|
#ifdef CYGPKG_HAL_NIOS2
|
|
|
|
{
|
|
|
|
.name = "updatezy1000firmware",
|
|
|
|
.mode = COMMAND_ANY,
|
2010-01-10 06:14:08 +00:00
|
|
|
.jim_handler = jim_zy1000_writefirmware,
|
2009-11-27 19:41:06 +00:00
|
|
|
.help = "writes firmware to flash",
|
2010-01-10 06:14:08 +00:00
|
|
|
/* .usage = "some_string", */
|
2009-11-27 19:41:06 +00:00
|
|
|
},
|
|
|
|
#endif
|
2009-11-30 07:43:49 +00:00
|
|
|
COMMAND_REGISTRATION_DONE
|
2009-11-27 19:41:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct jtag_interface zy1000_interface =
|
|
|
|
{
|
|
|
|
.name = "ZY1000",
|
|
|
|
.execute_queue = NULL,
|
|
|
|
.speed = zy1000_speed,
|
|
|
|
.commands = zy1000_commands,
|
|
|
|
.init = zy1000_init,
|
|
|
|
.quit = zy1000_quit,
|
|
|
|
.khz = zy1000_khz,
|
|
|
|
.speed_div = zy1000_speed_div,
|
|
|
|
.power_dropout = zy1000_power_dropout,
|
|
|
|
.srst_asserted = zy1000_srst_asserted,
|
|
|
|
};
|
|
|
|
|