|
From: Tom V. <ho...@gm...> - 2018-05-08 00:47:05
|
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 |