Hello OpenOCD Devs,
I have been working some JTAG enabled blocks (GPIOs, serial port, logic
analyzer) that are completely stand-alone, not dependent on a particular
CPU. The goal is to gradually have a set of open source debug options
similar to the closed source ones of Altera and Xilinx (jtag_uart,
In-System Signals & Probes, Signal Tap, ...)
Think about a configuration where an FPGA has multiple JTAG TAPs, one for a
CPU, one to control and observe some GPIOs, and another one for a JTAG
serial part that can be used by the CPU to interact with the CPU.
I prefer to have separate JTAG TAPs in one FPGA instead of one TAP with
multiple chains (like OpenRisc) because this makes it much easier to add
and remove functionality from a design, and because it also removes
dependencies between them, both for RTL and host PC code.
I want to use OpenOCD because I need to run GDB, which means I also need to
drive the other JTAG TAPs with OpenOCD.
Right now, I have solved the problem by creating a new target (jtag_gpio)
that implements a bunch of callbacks such as init, poll, etc and a number
of commands as well.
It stubs out pure CPU related callbacks to prevent OpenOCD from segfaulting
when you run particular commands (e.g. OpenOCD expects the 'resume'
callback to always be implemented).
An example is here:
https://github.com/tomverbeure/openocd/blob/jtag_gpio/src/target/jtag_gpio.c
It works fine.
However, there are a bunch of uglies.
1. as soon as a target is defined, a gdb server is lauched for it. There
doesn't seem to be a way to prevent that in the current code. It's not a
real problem as long as you don't make gdb connect to that port (if you do,
OpenOCD segfaults), but it's definitely ugly to even see the port to opened
in the logs. One way to avoid this is as follows:
static int gdb_target_add_one(struct target *target)
{
if (strcmp(gdb_port, "disabled") == 0) {
LOG_INFO("gdb port disabled");
return ERROR_OK;
}
> if (!target->type->get_gdb_reg_list){
> // Assume that this is not a valid GDB target when there's
no handler
> return ERROR_OK;
> }
...
2. The fact that I have to create all these callback stubs is a bit of a
cat-and-mouse game as well. Right now, I do it ad-hoc (when I see a
segfault, I stub it), but it would be much cleaner if the caller of these
callbacks would first check whether or not the callbacks were NULL and
ignore them if they are. Like this:
int target_resume(struct target *target, int current, target_addr_t address,
int handle_breakpoints, int debug_execution)
{
int retval;
/* We can't poll until after examine */
if (!target_was_examined(target)) {
LOG_ERROR("Target not examined yet");
return ERROR_FAIL;
}
target_call_event_callbacks(target, TARGET_EVENT_RESUME_START);
/* note that resume *must* be asynchronous. The CPU can halt before
* we poll. The CPU can even halt at the current PC as a result of
* a software breakpoint being inserted by (a bug?) the application.
*/
> if (target->type_resume){
retval = target->type->resume(target, current, address,
handle_breakpoints, debug_execution);
if (retval != ERROR_OK)
return retval;
> }
...
3. Right now, the only way to exchange data between OpenOCD and outside
clients is through the TCL interface. This is not ideal. The jsp_server of
OpenRisc uses its own telnet-like client instead. jsp_server is specific to
OpenRisc, but the specific parts are actually very minimal (just 2 places
in that code are calling *or1k* functions.) It would be great to have
something like generic_server which opens a socket that is either a pure
TCP socket or a telnet socket, with callbacks into custom handlers to
exchange data. This would be excellent for things like custom JTAG UARTs,
or large data exchange for ChipScope/SignalTap-like logic analyzers.
Here are my questions:
1. First and foremost, while my current way of creating non-CPU targets
works fine, I'm wondering if I missed something obvious in terms of how I
should have done this. Was it inevitable to implement code as a target, or
should I have used a different non-target primitive?
2. Are you guys open to patches that gradually expand targets to non-CPUs
and fix issues 1 and 2. For example, if a target would have a flag that
made it explicit that something was not a CPU, the hacks of 1 and 2 would
not be necessary.
3. Similarly, would there be interest in a generic socket implementation?
Other comments?
Thanks!
Tom
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel