This post is a follow-up to the DAC panel discussion we had yesterday on how to conquer hardware-dependent software development. Most of the panel turned into a very useful dialogue on virtual platforms and how they are created, not really discussing how to actually use them for easing low-level software development. We did get to software eventually though, and had another good dialogue with the audience. Thanks to the tough DAC participants who held out to the end of the last panel of the last day!
As is often the case, after the panel has ended, I realized several good and important points that I never got around to making… and of those one struck me as worthy of a blog post in its own right.It is the issue of how high-level synthesis can help software design.
At the end of the panel, the last comment from Kees Vissers of Xilinx pointed out that high-level synthesis is a very powerful way to build hardware. I think his point was that hardware and software are not that different… but the remark also got me thinking. If it is the case that high-level synthesis currently makes hardware creation easier, can’t it also be applied to software creation? In particular, if you have a HLS description of a piece of hardware, can’t you also generate its driver software?
I think that makes eminent sense, since one of the hard parts of doing device drivers is just getting the use of the programming registers of a device right. The programming register interface is a really strange thing if you think about it. It is not native to either software or hardware, really.
In hardware, you communicate between devices using fifos or signals or packet-based mechanisms which do not in general look like programming register writes. You move data by sending a stream of data directly, not word-by-word addressing registers. Similarly, on the software side, software units call each other using functions (or higher-level OS abstractions like signals or network packets). They do not put data into addressed registers…
Today, high-level synthesis as practiced in industry involves describing the function of a device in pretty abstract terms, so that the compiler can make smart decisions on the implementation details. It also makes it easier to try different alternatives in the implementation, trading size, speed, and power consumption against each other. Different types of concurrency and pipelining can be explored.
However, once we get to the hardware-software interface, we get rudely dropped into a world of manual detailing of an interface with no tool support to explore it or validate it. Why should that really be the case? I think that the hardware-software interface requires just as much care as the internals of the device. After all, it is the external face of the device, and if that is too hard to use, users will not get the full benefit of the device. Here are some previous posts on the nature of interfaces and why they matter: 1, 2, 3, 4.
So I would propose a different take on this, where you apply synthesis at a higher-level, and generate the hardware internals, the programming register interface, and the software driver from the same source. The interface you design for a device would be a set of function calls expressed in software terms, and thus relatively easy to use from software. Let’s call this SHLS, Software High-Level Synthesis. Or maybe Software-Level Synthesis, SLS.
I am well aware that most operating systems do not provide an interface to device drivers consisting of function calls… but rather rely on pretty non-semantic methods like read/write/ioctl. However, that is easy to overcome by generating a user-level interface library in addition to the raw device driver. Obviously, a tool like this would need some adaptation to apply to each operating system targeted. But that does not feel like something that cannot fairly easy be handled by a template system. Compared to the complexity of synthesizing hardware this feels pretty basic.
If you hide the software-hardware interface inside a black box like this, it can also be implemented in quite different and interesting ways. For example, you could imagine using a small memory-mapped buffer where you enter commands and data and then ask the hardware to “parse” it, rather than using discrete registers with immediate effects. Or you could optimize the coding of the relevant hardware operations into a bit-compacted representation no human would like, but which are no problem for the machine.
Another option is obviously to just stop at the hardware-software interface, but let the tool help the hardware designer build the programming register interface and explore various options for it. Not having to invent a register layout from scratch should make that job much easier.
Actually, over a decade ago there was a company called Aisys one of whose key mangers was Simon Napper, (currently CEO of Synfora) that had a tool called “DriveWay” that was aimed to doing a kind of device driver synthesis. It is hard finding a lot of information on the web for something so “old” and now out of business, but IEEE Computer had a short article written by Simon Napper in August 1998 issue called “Embedded-system design plays catch-up”.
To quote from the article, “My company’s DriveWay tool incorporates the processor information necessary to write a complete tailored board support package; this includes configurable device drivers and boot code; glue code that links to design-specific details such as the real-time OS, compiler, and hardware; and an extensive online knowledge base for the specific processor architecture. Our tool uses selections made via a graphical user interface to automatically build functioning device drivers and boot code. The tool incorporates peripheral configuration options and other choices that tailor driver code to a specific design.”
All good ideas come around again in slightly different forms! And of course companies like Duolog are building tools around the HW-SW register interfaces etc.
Thanks! Interesting.
Actually, IAR used to have a tool called MakeApp that did pretty much the same, including creating a valid chip configuration for a microcontroller. The problem MakeApp solved was both writing drivers and creating a valid chip configuration. For microcontrollers, it is and was very common to have each external pin configurable to a set of internal functions (it could be digital IO or a serial bus or interrupt line, etc.). Thus, the main value of MakeApp was in checking the validity of the configuration prior to deployment on the physical chip.
The problem with MakeApp was that someone had to enter all the information about the chip, usually reverse-engineering some of its behavior from hardware tests in the process. It was hard to sell at a decent enough price to pay for the development. On an ecosystem level, it was “profitable” in the sense that saved very many developers a few weeks each, leading to a globally reduced development burden. But each “few weeks” was not enough to pay for the license, and people do not like one-use tools like this.
Siemens used to have a similar tool for their chips too, which makes some more sense.
I think the key difference with what I am looking for is that for the case of new hardware (which does sometimes happen to be developed), you can leverage the information already present in the chip design flow to generate some software as well. Essentially, avoiding double-entry of information, and also allowing some interesting architecture exploration.
I came across these posts a bit late but yet feel like commenting on this.
While the approach of tools like DriveWay or MakeApp has been noteworthy towards high level synthesis i would like to say that this methodology is still driven from the “hardware view” of the engineering. There are other examples like Jungo’s WinDriver focusing on driver automation for specific class of devices like PCI, USB where devices are limited to few vendors. or Infineon’s DaVe Drive which helps in generating the application C-code along with all appropriate on chip peripheral driver code ( once again limited to micro controllers from Infineon), or Processor expert from Freescale which is a component oriented application builder which can generate system initialization code and the driver components also.
In many of the above cases the software code generation or synthesis is either limited to the specific hardware components/modules or only to a particular class of devices. In my opinion the existing software synthesis tools are yet to come off the age where they have to realize the input for high level synthesis also has to come from the software domain/design. As Jack mentions in his first post, high level synthesis of software is just not only generation of register access macros. We need to see how a set of these macros are inter oven to achieve the device functionality that is typically given by device ( IC) vendor in his application notes. To top up the complexity of this process ( software synthesis) operating systems as and when become a part of the design bring in their own limitations. The challenge of driver or firmware generation in such case is not just mapping or grouping of register access functionalities but to do that incorporating the operating system’s driver models.
At Vayavya Labs(http://www.vayavyalabs.com) we have been working on this topic for last three years. I would say we now have a high level device driver synthesis tool that can generate device drivers (ANSI C compliant code with .C and header files) pretty much for any off the shelf embedded device. The driver generator tools takes care of addressing the requirement of many of commonly available embedded Operating Systems. Hopefully industry associations like SPIRIT’s IP-XACT will slowly evolve towards system level synthesis in coming years.
I don’t think IP-XACT will help much here — you fundamentally need to describe how registers work and what to write to them to make things happen. And that is explicitly out of scope with IP-XACT.
I agree that the core issue is the generation of drivers within an operating system device driver framework.