This is an automated email from Gerrit. "zapb <d...@zapb.de>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8943
-- gerrit commit 7b06bebf97e2f46aa77a2753f124d2707146c77a Author: Marc Schink <d...@zapb.de> Date: Thu Feb 20 20:58:08 2025 +0000 adapter: Rework parallel port driver Make the driver more flexible and allow to specify adapter specific configuration in Tcl rather than in C, similar to the FTDI driver. The rework also includes coding style fixes and improvements of the documentation. All modifications are done such that backwards compatibility is ensured. Tested with Olimex ARM-JTAG cable [1] and APM32F103 target device on Linux and FreeBSD. The driver works on Linux using direct I/O and PPDEV. On FreeBSD, only PPDEV works. The build with direct I/O already failed before the patch. This problem will be fixed in a subsequent patch. The patch is not tested on Windows because there is no documentation for it. [1] https://www.olimex.com/Products/ARM/JTAG/ARM-JTAG/ Change-Id: Ib671d52a919eaf2959cf6365f2c8004257ae074c Signed-off-by: Marc Schink <d...@zapb.de> diff --git a/doc/openocd.texi b/doc/openocd.texi index bd6b3704a8..869efebb6e 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -529,9 +529,8 @@ debuggers to ARM Cortex based targets @url{http://www.keil.com/support/man/docs/ @section IBM PC Parallel Printer Port Based -The two well-known ``JTAG Parallel Ports'' cables are the Xilinx DLC5 -and the Macraigor Wiggler. There are many clones and variations of -these on the market. +The two well-known JTAG parallel port cables are the Xilinx DLC5 and the Macraigor Wiggler. +There are many clones and variations of these on the market. Note that parallel ports are becoming much less common, so if you have the choice you should probably avoid these adapters in favor @@ -553,7 +552,7 @@ produced, PDF schematics are easily found and it is easy to make. @* Link: @url{http://www.ccac.rwth-aachen.de/~michaels/index.php/hardware/armjtag} @item @b{Wiggler_ntrst_inverted} -@* Yet another variation - See the source code, src/jtag/parport.c +@* Yet another variation - see configuration in @file{interface/parport/wiggler-ntrst-inverted.cfg} @item @b{old_amt_wiggler} @* Unknown - probably not on the market today @@ -3078,61 +3077,102 @@ version, and target voltage. @end deffn @deffn {Interface Driver} {parport} -Supports PC parallel port bit-banging cables: -Wigglers, PLD download cable, and more. -These interfaces have several commands, used to configure the driver -before initializing the JTAG scan chain: -@deffn {Config Command} {parport cable} name -Set the layout of the parallel port cable used to connect to the target. -This is a write-once setting. -Currently valid cable @var{name} values include: +Supports PC parallel port bit-banging adapters. +The interface only supports JTAG as transport. + +The driver supports Linux, FreeBSD, and Windows. +However, the Windows support is untested and unmaintained. + +@deffn {Config Command} {parport port} port_number +Configure the number of the parallel port. + +When using PPDEV to access the parallel port, use the number of the parallel port file @file{/dev/parport} (Linux) or @file{/dev/ppi} (FreeBSD). +The default port number is 0. + +When using direct I/O, the number is the I/O port number. +The default port number is 0x378 (LTP1). +@end deffn + +@deffn {Config Command} {parport layout_signal} name mask +Configure the layout of the parallel port cable used to connect to the target. +The @var{name} must be one of the following signal names: @itemize @minus -@item @b{altium} Altium Universal JTAG cable. -@item @b{arm-jtag} Same as original wiggler except SRST and -TRST connections reversed and TRST is also inverted. -@item @b{chameleon} The Amontec Chameleon's CPLD when operated -in configuration mode. This is only used to -program the Chameleon itself, not a connected target. -@item @b{dlc5} The Xilinx Parallel cable III. -@item @b{flashlink} The ST Parallel cable. -@item @b{lattice} Lattice ispDOWNLOAD Cable -@item @b{old_amt_wiggler} The Wiggler configuration that comes with -some versions of -Amontec's Chameleon Programmer. The new version available from -the website uses the original Wiggler layout ('@var{wiggler}') -@item @b{triton} The parallel port adapter found on the -``Karo Triton 1 Development Board''. -This is also the layout used by the HollyGates design -(see @uref{http://www.lartmaker.nl/projects/jtag/}). -@item @b{wiggler} The original Wiggler layout, also supported by -several clones, such as the Olimex ARM-JTAG -@item @b{wiggler2} Same as original wiggler except an led is fitted on D5. -@item @b{wiggler_ntrst_inverted} Same as original wiggler except TRST is inverted. +@item @b{tdo}: JTAG TDO signal +@item @b{tdi} JTAG TDI signal +@item @b{tms} JTAG TMS signal +@item @b{tck} JTAG TCK signal +@item @b{trst} JTAG TRST signal +@item @b{output-invert} Virtual signal to invert an output pin +@item @b{input-invert} Virtual signal to invert an input pin +@item @b{led} LED indicator signal @end itemize + +The @var{mask} must be an 8-bit integer value. +A mask for the signals @b{tdo}, @b{tdi}, @b{tms}, and @b{tck} must be specified, all others are optional. + +The data and status pins of the parallel port are used as output and input pins, respectively. +The mapping between mask bits and the parallel port pins is given in the following table. + +@multitable @columnfractions .2 .1 .1 .1 .1 .1 .1 .1 .1 +@headitem Pin direction @tab Bit 7 @tab Bit 6 @tab Bit 5 @tab Bit 4 @tab Bit 3 @tab Bit 2 @tab Bit 1 @tab Bit 0 +@item Input +@tab ~11 +@tab 10 +@tab 12 +@tab 13 +@tab 15 +@tab - +@tab - +@tab - +@item Output +@tab 9 +@tab 8 +@tab 7 +@tab 6 +@tab 5 +@tab 4 +@tab 3 +@tab 2 +@end multitable + +For example, in order to configure the JTAG TDO signal on pin 11, bit 7 must be set in the mask: + +@example +parport layout_signal tdo 0x80 +@end example + +Since pin 11 is always inverted by hardware, you need to invert the signal for correct operation. +This can be done using the virtual @emph{input-invert} signal: + +@example +parport layout_signal input-invert 0x80 +@end example @end deffn -@deffn {Config Command} {parport port} [port_number] -Display either the address of the I/O port -(default: 0x378 for LPT1) or the number of the @file{/dev/parport} device. -If a parameter is provided, first switch to use that port. -This is a write-once setting. +@deffn {Config Command} {parport layout_init} mask +Configure the state of the output pins during the driver initialization. +For the mapping between bits and parallel port pins, see @command{parport layout_signal}. +@end deffn -When using PPDEV to access the parallel port, use the number of the parallel port: -@option{parport port 0} (the default). If @option{parport port 0x378} is specified -you may encounter a problem. +@deffn {Config Command} {parport layout_exit} mask +Configure the state of the output pins after driver shutdown. +The state is only set if enabled by the @command{parport write_on_exit} command. +For the mapping between bits and parallel port pins, see @command{parport layout_signal}. @end deffn -@deffn {Config Command} {parport toggling_time} [nanoseconds] -Displays how many nanoseconds the hardware needs to toggle TCK; -the parport driver uses this value to obey the -@command{adapter speed} configuration. -When the optional @var{nanoseconds} parameter is given, -that setting is changed before displaying the current value. +@deffn {Config Command} {parport write_on_exit} (@option{on}|@option{off}) +Configure whether the driver sets the value specified by @command{parport layout_exit} to the output pins on shutdown. +@end deffn + +@deffn {Config Command} {parport toggling_time} time +Configure how many nanoseconds the hardware needs to toggle TCK. +The driver uses this value to obey the @command{adapter speed} configuration. The default setting should work reasonably well on commodity PC hardware. However, you may want to calibrate for your specific hardware. + @quotation Tip To measure the toggling time with a logic analyzer or a digital storage oscilloscope, follow the procedure below: @@ -3140,15 +3180,18 @@ oscilloscope, follow the procedure below: > parport toggling_time 1000 > adapter speed 500 @end example + This sets the maximum JTAG clock speed of the hardware, but the actual speed probably deviates from the requested 500 kHz. Now, measure the time between the two closest spaced TCK transitions. You can use @command{runtest 1000} or something similar to generate a large set of samples. Update the setting to match your measurement: + @example > parport toggling_time <measured nanoseconds> @end example + Now the clock speed will be a better match for @command{adapter speed} command given in OpenOCD scripts and event handlers. @@ -3160,20 +3203,6 @@ match with the rate you specified in the @command{adapter speed} command; be conservative. @end quotation @end deffn - -@deffn {Config Command} {parport write_on_exit} (@option{on}|@option{off}) -This will configure the parallel driver to write a known -cable-specific value to the parallel interface on exiting OpenOCD. -@end deffn - -For example, the interface configuration file for a -classic ``Wiggler'' cable on LPT2 might look something like this: - -@example -adapter driver parport -parport port 0x278 -parport cable wiggler -@end example @end deffn @deffn {Interface Driver} {presto} diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c index 143f3bde1f..d9e61d2be6 100644 --- a/src/jtag/drivers/parport.c +++ b/src/jtag/drivers/parport.c @@ -20,7 +20,7 @@ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include <machine/sysarch.h> #include <machine/cpufunc.h> -#define ioperm(startport, length, enable)\ +#define ioperm(startport, length, enable) \ i386_set_ioperm((startport), (length), (enable)) #endif /* __FreeBSD__ */ @@ -45,67 +45,60 @@ #include <windows.h> #endif -// Parallel port cable description. -struct cable { - const char *name; - // Status port bit containing current TDO value. - uint8_t tdo_mask; - // Data port bit for TRST. - uint8_t trst_mask; - // Data port bit for TMD. - uint8_t tms_mask; - // Data port bit for TCK. - uint8_t tck_mask; - // Data port bit for TDI. - uint8_t tdi_mask; - // Data port bit for SRST. - uint8_t srst_mask; - // Data port bits that should be inverted. - uint8_t output_invert; - // Status port that should be inverted. - uint8_t input_invert; - // Initialize data port with this value. - uint8_t port_init; - // De-initialize data port with this value. - uint8_t port_exit; - // Data port bit for LED. - uint8_t led_mask; +enum signal { + SIGNAL_TDO = 0, + SIGNAL_TRST, + SIGNAL_TMS, + SIGNAL_TCK, + SIGNAL_TDI, + SIGNAL_SRST, + SIGNAL_OUTPUT_INVERT, + SIGNAL_INPUT_INVERT, + SIGNAL_LED, }; -static const struct cable cables[] = { - /* name tdo trst tms tck tdi srst o_inv i_inv init exit led */ - { "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x80, 0x00 }, - { "wiggler2", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x00, 0x20 }, - { "wiggler_ntrst_inverted", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x11, 0x80, 0x80, 0x80, 0x00 }, - { "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80, 0x80, 0x00 }, - { "arm-jtag", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x01, 0x80, 0x80, 0x80, 0x00 }, - { "chameleon", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }, - { "dlc5", 0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00 }, - { "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }, - { "lattice", 0x40, 0x10, 0x04, 0x02, 0x01, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00 }, - { "flashlink", 0x20, 0x10, 0x02, 0x01, 0x04, 0x20, 0x30, 0x20, 0x00, 0x00, 0x00 }, -/* Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows: - HARD TCK - Target TCK - HARD TMS - Target TMS - HARD TDI - Target TDI - HARD TDO - Target TDO - SOFT TCK - Target TRST - SOFT TDI - Target SRST -*/ - { "altium", 0x10, 0x20, 0x04, 0x02, 0x01, 0x80, 0x00, 0x00, 0x10, 0x00, 0x08 }, - { "aspo", 0x10, 0x01, 0x04, 0x08, 0x02, 0x10, 0x17, 0x00, 0x17, 0x17, 0x00 }, - { NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +const char *signal_names[] = { + [SIGNAL_TDO] = "tdo", + [SIGNAL_TRST] = "trst", + [SIGNAL_TMS] = "tms", + [SIGNAL_TCK] = "tck", + [SIGNAL_TDI] = "tdi", + [SIGNAL_SRST] = "srst", + [SIGNAL_OUTPUT_INVERT] = "output-invert", + [SIGNAL_INPUT_INVERT] = "input-invert", + [SIGNAL_LED] = "led", }; -// Configuration variables. -static char *parport_cable; +static enum signal required_signals[] = { + SIGNAL_TDO, + SIGNAL_TMS, + SIGNAL_TCK, + SIGNAL_TDI, +}; + +static bool find_signal_by_name(const char *name, enum signal *signal) +{ + for (size_t i = 0; i < ARRAY_SIZE(signal_names); i++) { + if (!strcmp(name, signal_names[i])) { + *signal = i; + return true; + } + } + + return false; +} + +// Initialize data port with this value. +static uint8_t parport_init_state; +// De-initialize data port with this value. +static uint8_t parport_exit_state; +static uint8_t parport_signal_masks[ARRAY_SIZE(signal_names)]; static uint16_t parport_port; -static bool parport_exit; +static bool parport_write_exit_state; static uint32_t parport_toggling_time_ns = 1000; static int wait_states; // Interface variables. -static const struct cable *cable; static uint8_t dataport_value; #if PARPORT_USE_PPDEV == 1 @@ -125,7 +118,7 @@ static enum bb_value parport_read(void) data = inb(statusport); #endif - if ((data ^ cable->input_invert) & cable->tdo_mask) + if ((data ^ parport_signal_masks[SIGNAL_INPUT_INVERT]) & parport_signal_masks[SIGNAL_TDO]) return BB_HIGH; else return BB_LOW; @@ -133,8 +126,7 @@ static enum bb_value parport_read(void) static inline void parport_write_data(void) { - uint8_t output; - output = dataport_value ^ cable->output_invert; + const uint8_t output = dataport_value ^ parport_signal_masks[SIGNAL_OUTPUT_INVERT]; #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPWDATA, &output); @@ -149,24 +141,28 @@ static inline void parport_write_data(void) static int parport_write(int tck, int tms, int tdi) { - int i = wait_states + 1; + const uint8_t tck_mask = parport_signal_masks[SIGNAL_TCK]; if (tck) - dataport_value |= cable->tck_mask; + dataport_value |= tck_mask; else - dataport_value &= ~cable->tck_mask; + dataport_value &= ~tck_mask; + + const uint8_t tms_mask = parport_signal_masks[SIGNAL_TMS]; if (tms) - dataport_value |= cable->tms_mask; + dataport_value |= tms_mask; else - dataport_value &= ~cable->tms_mask; + dataport_value &= ~tms_mask; + + const uint8_t tdi_mask = parport_signal_masks[SIGNAL_TDI]; if (tdi) - dataport_value |= cable->tdi_mask; + dataport_value |= tdi_mask; else - dataport_value &= ~cable->tdi_mask; + dataport_value &= ~tdi_mask; - while (i-- > 0) + for (int i = 0; i < wait_states + 1; i++) parport_write_data(); return ERROR_OK; @@ -177,15 +173,19 @@ static int parport_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); + const uint8_t trst_mask = parport_signal_masks[SIGNAL_TRST]; + if (trst == 0) - dataport_value |= cable->trst_mask; + dataport_value |= trst_mask; else if (trst == 1) - dataport_value &= ~cable->trst_mask; + dataport_value &= ~trst_mask; + + const uint8_t srst_mask = parport_signal_masks[SIGNAL_SRST]; if (srst == 0) - dataport_value |= cable->srst_mask; + dataport_value |= srst_mask; else if (srst == 1) - dataport_value &= ~cable->srst_mask; + dataport_value &= ~srst_mask; parport_write_data(); @@ -194,10 +194,12 @@ static int parport_reset(int trst, int srst) static int parport_led(bool on) { + const uint8_t led_mask = parport_signal_masks[SIGNAL_LED]; + if (on) - dataport_value |= cable->led_mask; + dataport_value |= led_mask; else - dataport_value &= ~cable->led_mask; + dataport_value &= ~led_mask; parport_write_data(); @@ -213,11 +215,12 @@ static int parport_speed(int speed) static int parport_khz(int khz, int *jtag_speed) { if (!khz) { - LOG_DEBUG("RCLK not supported"); + LOG_ERROR("RCLK is not supported"); return ERROR_FAIL; } *jtag_speed = 499999 / (khz * parport_toggling_time_ns); + return ERROR_OK; } @@ -226,32 +229,35 @@ static int parport_speed_div(int speed, int *khz) uint32_t denominator = (speed + 1) * parport_toggling_time_ns; *khz = (499999 + denominator) / denominator; + return ERROR_OK; } #if PARPORT_USE_GIVEIO == 1 -static int parport_get_giveio_access(void) +static bool parport_get_giveio_access(void) { - HANDLE h; OSVERSIONINFO version; version.dwOSVersionInfoSize = sizeof(version); if (!GetVersionEx(&version)) { errno = EINVAL; - return -1; + return false; } + if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) - return 0; + return true; + + HANDLE h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); - h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { errno = ENODEV; - return -1; + return false; } CloseHandle(h); - return 0; + return true; } #endif @@ -263,78 +269,65 @@ static const struct bitbang_interface parport_bitbang = { static int parport_init(void) { - const struct cable *cur_cable; -#if PARPORT_USE_PPDEV == 1 - char buffer[256]; -#endif - - cur_cable = cables; - - if (!parport_cable) { - parport_cable = strdup("wiggler"); - LOG_WARNING("No parport cable specified, using default 'wiggler'"); - } + for (size_t i = 0; i < ARRAY_SIZE(required_signals); i++) { + const enum signal signal = required_signals[i]; - while (cur_cable->name) { - if (!strcmp(cur_cable->name, parport_cable)) { - cable = cur_cable; - break; + if (!parport_signal_masks[signal]) { + LOG_ERROR("Required signal mask '%s' is not specified", + signal_names[signal]); + return ERROR_FAIL; } - cur_cable++; - } - - if (!cable) { - LOG_ERROR("No matching cable found for %s", parport_cable); - return ERROR_JTAG_INIT_FAILED; } - dataport_value = cable->port_init; + dataport_value = parport_init_state; #if PARPORT_USE_PPDEV == 1 if (device_handle > 0) { - LOG_ERROR("device is already opened"); + LOG_ERROR("Parallel port is already open"); return ERROR_JTAG_INIT_FAILED; } + char device_path[256]; + #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - LOG_DEBUG("opening /dev/ppi%d...", parport_port); + snprintf(device_path, sizeof(device_path), "/dev/ppi%d", parport_port); +#else + snprintf(device_path, sizeof(device_path), "/dev/parport%d", parport_port); +#endif /* __FreeBSD__, __FreeBSD_kernel__ */ - snprintf(buffer, 256, "/dev/ppi%d", parport_port); - device_handle = open(buffer, O_WRONLY); -#else /* not __FreeBSD__, __FreeBSD_kernel__ */ - LOG_DEBUG("opening /dev/parport%d...", parport_port); + LOG_DEBUG("Using parallel port %s", device_path); - snprintf(buffer, 256, "/dev/parport%d", parport_port); - device_handle = open(buffer, O_WRONLY); -#endif /* __FreeBSD__, __FreeBSD_kernel__ */ + device_handle = open(device_path, O_WRONLY); if (device_handle < 0) { int err = errno; - LOG_ERROR("cannot open device. check it exists and that user read and write rights are set. errno=%d", err); + LOG_ERROR("Failed to open parallel port %s (errno = %d)", device_path, + err); + LOG_ERROR("Check whether the device exists and if you have the required access rights"); return ERROR_JTAG_INIT_FAILED; } - LOG_DEBUG("...open"); - #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) - int i = ioctl(device_handle, PPCLAIM); + int retval = ioctl(device_handle, PPCLAIM); - if (i < 0) { - LOG_ERROR("cannot claim device"); + if (retval < 0) { + LOG_ERROR("Failed to claim parallel port %s", device_path); return ERROR_JTAG_INIT_FAILED; } - i = PARPORT_MODE_COMPAT; - i = ioctl(device_handle, PPSETMODE, &i); - if (i < 0) { - LOG_ERROR(" cannot set compatible mode to device"); + int value = PARPORT_MODE_COMPAT; + retval = ioctl(device_handle, PPSETMODE, &value); + + if (retval < 0) { + LOG_ERROR("Cannot set compatible mode to device"); return ERROR_JTAG_INIT_FAILED; } - i = IEEE1284_MODE_COMPAT; - i = ioctl(device_handle, PPNEGOT, &i); - if (i < 0) { - LOG_ERROR("cannot set compatible 1284 mode to device"); + value = IEEE1284_MODE_COMPAT; + retval = ioctl(device_handle, PPNEGOT, &value); + + if (retval < 0) { + LOG_ERROR("Cannot set compatible 1284 mode to device"); return ERROR_JTAG_INIT_FAILED; } #endif /* not __FreeBSD__, __FreeBSD_kernel__ */ @@ -342,24 +335,24 @@ static int parport_init(void) #else /* not PARPORT_USE_PPDEV */ if (!parport_port) { parport_port = 0x378; - LOG_WARNING("No parport port specified, using default '0x378' (LPT1)"); + LOG_WARNING("No parallel port specified, using default 0x378 (LPT1)"); } + LOG_DEBUG("Using parallel port 0x%x", parport_port); + dataport = parport_port; statusport = parport_port + 1; - LOG_DEBUG("requesting privileges for parallel port 0x%lx...", dataport); #if PARPORT_USE_GIVEIO == 1 - if (parport_get_giveio_access() != 0) { + if (!parport_get_giveio_access()) { #else /* PARPORT_USE_GIVEIO */ if (ioperm(dataport, 3, 1) != 0) { #endif /* PARPORT_USE_GIVEIO */ - LOG_ERROR("missing privileges for direct i/o"); + LOG_ERROR("Missing privileges for direct I/O"); return ERROR_JTAG_INIT_FAILED; } - LOG_DEBUG("...privileges granted"); - // Make sure parallel port is in right mode (clear tristate and interrupt. + // Make sure parallel port is in right mode (clear tristate and interrupt). #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(parport_port + 2, 0x0); #else @@ -370,8 +363,10 @@ static int parport_init(void) if (parport_reset(0, 0) != ERROR_OK) return ERROR_FAIL; + if (parport_write(0, 0, 0) != ERROR_OK) return ERROR_FAIL; + if (parport_led(true) != ERROR_OK) return ERROR_FAIL; @@ -385,94 +380,117 @@ static int parport_quit(void) if (parport_led(false) != ERROR_OK) return ERROR_FAIL; - if (parport_exit) { - dataport_value = cable->port_exit; + if (parport_write_exit_state) { + dataport_value = parport_exit_state; parport_write_data(); } - free(parport_cable); - parport_cable = NULL; - return ERROR_OK; } COMMAND_HANDLER(parport_handle_port_command) { - if (CMD_ARGC == 1) { - // Only if the port wasn't overwritten by cmdline. - if (!parport_port) { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], parport_port); - } else { - LOG_ERROR("The parport port was already configured!"); - return ERROR_FAIL; - } + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + // Only if the port wasn't overwritten by command-line. + if (parport_port > 0) { + command_print(CMD, "The parallel port is already configured"); + return ERROR_FAIL; } - command_print(CMD, "parport port = 0x%" PRIx16 "", parport_port); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], parport_port); return ERROR_OK; } -COMMAND_HANDLER(parport_handle_cable_command) +COMMAND_HANDLER(parport_handle_layout_signal_command) { - if (!CMD_ARGC) - return ERROR_OK; - - // Only if the cable name wasn't overwritten by cmdline. - if (!parport_cable) { - // TODO: REVISIT first verify that it's listed in cables[]. - parport_cable = malloc(strlen(CMD_ARGV[0]) + sizeof(char)); - if (!parport_cable) { - LOG_ERROR("Out of memory"); - return ERROR_FAIL; - } - strcpy(parport_cable, CMD_ARGV[0]); + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + const char *signal_name = CMD_ARGV[0]; + enum signal signal; + + if (!find_signal_by_name(signal_name, &signal)) { + command_print(CMD, "invalid signal name '%s'", signal_name); + return ERROR_COMMAND_ARGUMENT_INVALID; } - // TODO: REVISIT it's probably worth returning the current value. + uint8_t mask; + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], mask); + + parport_signal_masks[signal] = mask; + + return ERROR_OK; +} + +COMMAND_HANDLER(parport_handler_layout_init_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], parport_init_state); + + return ERROR_OK; +} + +COMMAND_HANDLER(parport_handler_layout_exit_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], parport_exit_state); return ERROR_OK; } +// This command is only for backward compatibility and will be removed in the +// future. +COMMAND_HANDLER(parport_handle_cable_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + return command_run_linef(CMD_CTX, "parport_select_cable %s", CMD_ARGV[0]); +} + COMMAND_HANDLER(parport_handle_write_on_exit_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], parport_exit); + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], parport_write_exit_state); return ERROR_OK; } COMMAND_HANDLER(parport_handle_toggling_time_command) { - if (CMD_ARGC == 1) { - uint32_t ns; - int retval = parse_u32(CMD_ARGV[0], &ns); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - if (retval != ERROR_OK) - return retval; + uint32_t toggling_time; - if (!ns) { - LOG_ERROR("0 ns is not a valid parport toggling time"); - return ERROR_FAIL; - } + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], toggling_time); - parport_toggling_time_ns = ns; - retval = adapter_get_speed(&wait_states); - if (retval != ERROR_OK) { - /* - * If adapter_get_speed fails then the clock_mode has - * not been configured, this happens if toggling_time is - * called before the adapter speed is set. - */ - LOG_INFO("no parport speed set - defaulting to zero wait states"); - wait_states = 0; - } + if (!toggling_time) { + command_print(CMD, "toggling time must not be 0 ns"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - command_print(CMD, "parport toggling time = %" PRIu32 " ns", - parport_toggling_time_ns); + parport_toggling_time_ns = toggling_time; + int retval = adapter_get_speed(&wait_states); + + if (retval != ERROR_OK) { + /* + * If adapter_get_speed fails then the clock_mode has not been + * configured, this happens if toggling_time is called before the + * adapter speed is set. + */ + LOG_INFO("No parallel port speed set, using zero wait states"); + wait_states = 0; + } return ERROR_OK; } @@ -482,35 +500,52 @@ static const struct command_registration parport_subcommand_handlers[] = { .name = "port", .handler = parport_handle_port_command, .mode = COMMAND_CONFIG, - .help = "Display the address of the I/O port (e.g. 0x378) " - "or the number of the '/dev/parport' device used. " - "If a parameter is provided, first change that port.", - .usage = "[port_number]", + .help = "Configure the address of the I/O port (e.g. 0x378) " + "or the number of the '/dev/parport' (Linux) or '/dev/ppi' (FreeBSD) device used", + .usage = "port_number", + }, + { + .name = "layout_signal", + .handler = parport_handle_layout_signal_command, + .mode = COMMAND_CONFIG, + .help = "Configure the signal layout of the parallel port", + .usage = "name mask", + }, + { + .name = "layout_init", + .handler = parport_handler_layout_init_command, + .mode = COMMAND_CONFIG, + .help = "Configure the output pin states during driver initialization", + .usage = "mask", + }, + { + .name = "layout_exit", + .handler = parport_handler_layout_exit_command, + .mode = COMMAND_CONFIG, + .help = "Configure the output pin states after driver shutdown", + .usage = "mask", }, { .name = "cable", .handler = parport_handle_cable_command, .mode = COMMAND_CONFIG, .help = "Set the layout of the parallel port cable " - "used to connect to the target.", - // TODO: REVISIT there's no way to list layouts we know. - .usage = "[layout]", + "used to connect to the target", + .usage = "cable", }, { .name = "write_on_exit", .handler = parport_handle_write_on_exit_command, .mode = COMMAND_CONFIG, - .help = "Configure the parallel driver to write " - "a known value to the parallel interface on exit.", + .help = "Configure the driver to write a value to the parallel port on shutdown", .usage = "('on'|'off')", }, { .name = "toggling_time", .handler = parport_handle_toggling_time_command, .mode = COMMAND_CONFIG, - .help = "Displays or assigns how many nanoseconds it " - "takes for the hardware to toggle TCK.", - .usage = "[nanoseconds]", + .help = "Configure how many nanoseconds it takes for the hardware to toggle TCK", + .usage = "time", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index 2d8ebf0410..28a237aa57 100644 --- a/src/jtag/startup.tcl +++ b/src/jtag/startup.tcl @@ -359,6 +359,27 @@ proc parport_cable args { eval parport cable $args } +lappend _telnet_autocomplete_skip parport_select_cable +proc parport_select_cable {cable} { + echo "DEPRECATED! Do not use 'parport cable' but use a cable configuration file in interface/parport" + + switch $cable { + "wiggler" { source [find interface/parport/wiggler.cfg] } + "wiggler2" { source [find interface/parport/wiggler2.cfg] } + "wiggler_ntrst_inverted" { source [find interface/parport/wiggler-ntrst-inverted.cfg] } + "old_amt_wiggler" { source [find interface/parport/amt-wiggler-old.cfg ] } + "arm-jtag" { source [find interface/parport/arm-jtag.cfg] } + "chameleon" { source [find interface/parport/chameleon.cfg] } + "dlc5" { source [find interface/parport/dlc5.cfg] } + "triton" { source [find interface/parport/triton.cfg] } + "lattice" { source [find interface/parport/lattice.cfg] } + "flashlink" { source [find interface/parport/flashlink.cfg] } + "altium" { source [find interface/parport/altium.cfg] } + "aspo" { source [find interface/parport/aspo.cfg] } + default { error "invalid parallel port cable '$cable'" } + } +} + lappend _telnet_autocomplete_skip parport_write_on_exit proc parport_write_on_exit args { echo "DEPRECATED! use 'parport write_on_exit' not 'parport_write_on_exit'" diff --git a/tcl/interface/parport/altium.cfg b/tcl/interface/parport/altium.cfg new file mode 100644 index 0000000000..c33c247c8e --- /dev/null +++ b/tcl/interface/parport/altium.cfg @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows: +# +# HARD TCK - Target TCK +# HARD TMS - Target TMS +# HARD TDI - Target TDI +# HARD TDO - Target TDO +# SOFT TCK - Target TRST +# SOFT TDI - Target SRST + +adapter driver parport + +parport layout_signal tdo 0x10 +parport layout_signal trst 0x20 +parport layout_signal tms 0x04 +parport layout_signal tck 0x02 +parport layout_signal tdi 0x01 +parport layout_signal srst 0x80 +parport layout_signal led 0x08 + +parport layout_init 0x10 +parport layout_exit 0x0 diff --git a/tcl/interface/parport/amt-wiggler-old.cfg b/tcl/interface/parport/amt-wiggler-old.cfg new file mode 100644 index 0000000000..df165e23dd --- /dev/null +++ b/tcl/interface/parport/amt-wiggler-old.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x80 +parport layout_signal trst 0x01 +parport layout_signal tms 0x02 +parport layout_signal tck 0x04 +parport layout_signal tdi 0x08 +parport layout_signal srst 0x10 +parport layout_signal output-invert 0x11 +parport layout_signal input-invert 0x80 + +parport layout_init 0x80 +parport layout_exit 0x80 diff --git a/tcl/interface/parport/arm-jtag.cfg b/tcl/interface/parport/arm-jtag.cfg new file mode 100644 index 0000000000..f14f4922a2 --- /dev/null +++ b/tcl/interface/parport/arm-jtag.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x80 +parport layout_signal trst 0x01 +parport layout_signal tms 0x02 +parport layout_signal tck 0x04 +parport layout_signal tdi 0x08 +parport layout_signal srst 0x10 +parport layout_signal output-invert 0x01 +parport layout_signal input-invert 0x80 + +parport layout_init 0x80 +parport layout_exit 0x80 diff --git a/tcl/interface/parport/aspo.cfg b/tcl/interface/parport/aspo.cfg new file mode 100644 index 0000000000..29a9df7117 --- /dev/null +++ b/tcl/interface/parport/aspo.cfg @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x10 +parport layout_signal trst 0x01 +parport layout_signal tms 0x04 +parport layout_signal tck 0x08 +parport layout_signal tdi 0x02 +parport layout_signal srst 0x10 +parport layout_signal output-invert 0x17 + +parport layout_init 0x17 +parport layout_exit 0x17 diff --git a/tcl/interface/parport/chameleon.cfg b/tcl/interface/parport/chameleon.cfg new file mode 100644 index 0000000000..3e19cdac42 --- /dev/null +++ b/tcl/interface/parport/chameleon.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x80 +parport layout_signal tms 0x04 +parport layout_signal tck 0x01 +parport layout_signal tdi 0x02 +parport layout_signal input-invert 0x80 + +parport layout_init 0x0 +parport layout_exit 0x0 diff --git a/tcl/interface/parport/dlc5.cfg b/tcl/interface/parport/dlc5.cfg index 24acea7a95..ae8caf51f6 100644 --- a/tcl/interface/parport/dlc5.cfg +++ b/tcl/interface/parport/dlc5.cfg @@ -1,17 +1,13 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# # Xilinx Parallel Cable III 'DLC 5' (and various clones) -# -# http://www.xilinx.com/itp/xilinx4/data/docs/pac/appendixb.html -# - -if { [info exists PARPORTADDR] } { - set _PARPORTADDR $PARPORTADDR -} else { - set _PARPORTADDR 0 -} adapter driver parport -parport port $_PARPORTADDR -parport cable dlc5 + +parport layout_signal tdo 0x10 +parport layout_signal tms 0x04 +parport layout_signal tck 0x02 +parport layout_signal tdi 0x01 + +parport layout_init 0x10 +parport layout_exit 0x10 diff --git a/tcl/interface/parport/flashlink.cfg b/tcl/interface/parport/flashlink.cfg new file mode 100644 index 0000000000..634a6fc928 --- /dev/null +++ b/tcl/interface/parport/flashlink.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x20 +parport layout_signal trst 0x10 +parport layout_signal tms 0x02 +parport layout_signal tck 0x01 +parport layout_signal tdi 0x04 +parport layout_signal srst 0x20 +parport layout_signal output-invert 0x30 +parport layout_signal input-invert 0x20 + +parport layout_init 0x0 +parport layout_exit 0x0 diff --git a/tcl/interface/parport/lattice.cfg b/tcl/interface/parport/lattice.cfg new file mode 100644 index 0000000000..0b8dfe4a19 --- /dev/null +++ b/tcl/interface/parport/lattice.cfg @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x40 +parport layout_signal trst 0x10 +parport layout_signal tms 0x04 +parport layout_signal tck 0x02 +parport layout_signal tdi 0x01 +parport layout_signal srst 0x08 + +parport layout_init 0x18 +parport layout_exit 0x18 diff --git a/tcl/interface/parport/triton.cfg b/tcl/interface/parport/triton.cfg new file mode 100644 index 0000000000..092b55a4f1 --- /dev/null +++ b/tcl/interface/parport/triton.cfg @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x80 +parport layout_signal trst 0x08 +parport layout_signal tms 0x04 +parport layout_signal tck 0x01 +parport layout_signal tdi 0x02 +parport layout_signal input-invert 0x80 + +parport layout_init 0x0 +parport layout_exit 0x0 diff --git a/tcl/interface/parport/wiggler-ntrst-inverted.cfg b/tcl/interface/parport/wiggler-ntrst-inverted.cfg new file mode 100644 index 0000000000..639516ae58 --- /dev/null +++ b/tcl/interface/parport/wiggler-ntrst-inverted.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x80 +parport layout_signal trst 0x10 +parport layout_signal tms 0x02 +parport layout_signal tck 0x04 +parport layout_signal tdi 0x08 +parport layout_signal srst 0x01 +parport layout_signal output-invert 0x11 +parport layout_signal input-invert 0x80 + +parport layout_init 0x80 +parport layout_exit 0x80 diff --git a/tcl/interface/parport/wiggler.cfg b/tcl/interface/parport/wiggler.cfg index b9fceeb852..4e53f57f9b 100644 --- a/tcl/interface/parport/wiggler.cfg +++ b/tcl/interface/parport/wiggler.cfg @@ -1,21 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# -# Parallel port wiggler (many clones available) on port 0x378 -# -# Addresses: 0x378/LPT1 or 0x278/LPT2 ... -# +adapter driver parport -if { [info exists PARPORTADDR] } { - set _PARPORTADDR $PARPORTADDR -} else { - if {$tcl_platform(platform) eq "windows"} { - set _PARPORTADDR 0x378 - } { - set _PARPORTADDR 0 - } -} +parport layout_signal tdo 0x80 +parport layout_signal trst 0x10 +parport layout_signal tms 0x02 +parport layout_signal tck 0x04 +parport layout_signal tdi 0x08 +parport layout_signal srst 0x01 +parport layout_signal output-invert 0x01 +parport layout_signal input-invert 0x80 -adapter driver parport -parport port $_PARPORTADDR -parport cable wiggler +parport layout_init 0x80 +parport layout_exit 0x80 diff --git a/tcl/interface/parport/wiggler2.cfg b/tcl/interface/parport/wiggler2.cfg new file mode 100644 index 0000000000..d4a0c41c0b --- /dev/null +++ b/tcl/interface/parport/wiggler2.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x80 +parport layout_signal trst 0x10 +parport layout_signal tms 0x02 +parport layout_signal tck 0x04 +parport layout_signal tdi 0x08 +parport layout_signal srst 0x01 +parport layout_signal output-invert 0x01 +parport layout_signal input-invert 0x80 +parport layout_signal led 0x20 + +parport layout_init 0x80 +parport layout_exit 0x0 --