Published in April / May 2009 issue of Chip Design Magazine
Audio-Decode Application Is Realized on Open Virtual PlatformWith software development eating up more resources than hardware development, it’s time for a freer and more open approach.
Software is becoming increasingly more important in system design. In fact, software development for embedded systems now requires more resources than hardware development. Software also is becoming increasingly complex, which is leading to problems with bugs, schedules, and code maintenance and updates. This situation is amplified in the case of leading-edge integrated circuits (ICs) or systems-on-a-chip (SoCs) that utilize multiple processor cores. If the SoC is modeled in enough detail, however, the software developers can use the model as a virtual development environment or platform. This approach allows software to be comprehensively tested earlier in the development cycle. The software, which is compiled for the silicon and then run or simulated on a virtual platform, can be more rigorously tested than on the actual hardware. The virtual platform’s observability and controllability also make it easier to debug the code.
This article will illustrate how a virtual platform is constructed and a new Universal Serial Bus (USB) peripheral is created using the specific example of an audio-decode application. The virtual platform utilizes a Tensilica Diamond 570T core. The virtual-platform technology is open source from Open Virtual Platforms (www.OVPworld.org). The example development services were provided by Sibridge Technologies (www.sibridgetech.com).
Figure 1: Shown is a block diagram of the audio-decode platform.
Figure 1 shows the block diagram for this example. It includes the following features:
- Virtual platform consisting of a Tensilica Diamond 570T core model, USB peripheral model, and memory model running under Windows XP
- Demo application decoding an Ogg Vorbis-compressed audio file and playing the output using USB speakers
- Decompression done on the Tensilica core as a pure C implementation
- A binary-intercept library providing the link between the USB peripheral model and the Windows USB-host peripheral device driver layer
The Tensilica Diamond 570T core model is included in the virtual platform through the use of a simple encapsulation layer file provided by OVP. The USB peripheral model and the intercept library were developed by Sibridge. They are available through the OVP website. Sibridge also developed the audio-decode demo application. The individual models, platform, and OVPsim simulator are all available free of charge from the OVP website
OVP Virtual-Platform Technology
The virtual platform that’s used to simulate the system must handle SoC complexity while delivering the performance required to verify billions of operational “cycles.” To reduce integration risks and costs, the solution must permit model interoperability and the use of legacy models. End users, tool and intellectual-property (IP) developers, and service providers all must be able to contribute to the platform-development infrastructure. The OVP-based platform satisfies these criteria by enabling software simulations that execute at hundreds of millions of instructions per second (MIPS). Aside from handling multicore architectures, it has a robust set of application programming interfaces (APIs) for the ease of modeling processors, components, and platforms. The utilization of an open-source modeling approach enables the community to drive technology development further while leveraging existing work.
OVPsim is a dynamic linked library that implements Imperas simulation technology. It contains implementations of all of the platform API interface functions that enable the instantiation, interconnection, and simulation of complex multiprocessor platforms containing arbitrary local and shared-memory topologies. Currently, OVPsim is available only on Windows XP. But a commercial simulation product that’s completely compatible with the OVPsim APIs is available from Imperas. It runs on both Windows XP and Linux.
The processor models developed using OVP are instruction accurate. They are therefore suitable for the functional simulation, verification, and debug of applications. At the heart of the OVP simulation technology is a just-in-time (JIT) compiler, which translates the processor instructions into native x86 instructions.
The binary intercept technology built into OVPsim allows additional native code to execute when the application program hits a defined symbol or address. Any code that is executing on a processor or peripheral model can be intercepted. In general terms, this technology can be used to allow the use of a real device in the simulated system’s host system.
“Semi-hosting” is provided by a special case of intercepting, which is supplied to support features that are specific to a particular C library and processor. Semi-hosting provides intercepts on standard library function calls so that features in the host system can be used. Examples include the console output and file system. For example, intercepting “open” and “read” can allow a file to be opened and read on the host file system. In this example, the USB peripheral model has some features intercepted by a specially written intercept library. A real USB port can thus be used on the host PC for audio playback with attached USB speakers.
OVP provides several options for modeling memory at arbitrary levels of granularity (down to a single byte, if required) and in different topologies ranging from individual processor memory to shared and system memory. Memory can be instantiated as simple RAMs and ROMs or more complex L1 and L2 caches. In this example, memory was implemented as instances of OVPsim RAM.
The audio-decode platform is built around the Tensilica processor core. In addition to the processor core, the SoC (virtual platform) consists of the USB host peripheral and memory for storing program and application data. The USB host peripheral leverages the intercept library to stream data to the USB speakers.
Platform components are instantiated and interconnected using the ICM APIs provided by OVP. The processor core is instantiated using the icmNewProcessor() API with the type of processor core (in this case, Tensilica) and other required attributes as function parameters.
Figure 2: The audio-decode platform is pictured here.
const char *diamondCore = icmGetVlnvString(
NULL, "imperas.com", "processor", "diamondCore", "1.0", "model"
// instantiate main processors
printf("instantiate main processors\n");
icmProcessorP processor = icmNewProcessor(
"cpu1", // CPU name
“DC570T”, // CPU type
0, // CPU cpuId
0, // CPU model flags
32, // address bits
diamondCore, // model file
"modelAttrs", // morpher attributes
0, // enable tracing etc
0, // user-defined attributes
0, // semi-hosting file
0 // semi-hosting attributes
// connect the processor instruction and data busses to the bus
icmConnectProcessorBusses(processor, bus, bus);
Two memory sections, “mem1” and “mem2,” are instantiated using icmNewMemory()with read/write access permission with required memory size as function arguments. The processor-memory space is organized into sections as illustrated in Figure 3.
The USB peripheral is instantiated using icmNewPSE(). A memory window of size 0x140 is created for implementing USB peripheral registers in the processor-memory map. All of the components are interconnected using a 32-bit bus with read/write access permission. To allow the USB peripheral to directly access processor-memory space, a master port is created. This port can access processor-memory space in the range of 0x0000 0000 to 0xFFFF FFFF.
Figure 3: The processor-memory space is organized into sections.
// create two memory regions mapping all memory except the DMAC registers
icmMemoryP mem2 = icmNewMemory("mem2", ICM_PRIV_RWX, 0x7FFFFEBF);
icmMemoryP mem1 = icmNewMemory("mem1", ICM_PRIV_RWX, 0x7fffffff);
// connect memories to the bus
icmConnectMemoryToBus(bus, "sp", mem2, 0x80000140);
icmConnectMemoryToBus(bus, "sp", mem1, 0x00000000);
const char *usbPer = icmGetVlnvString(PSE_PERIPHERAL_LIB,
"sibridgetech.com", "peripheral", "usbPeripheralSemiHost ", "1.0", "pse");
const char *usbPerIntercept = icmGetVlnvString(PSE_PERIPHERAL_LIB,
"sibridgetech.com", "peripheral", "usbPeripheralSemiHost ", "1.0", "model");
// instantiate the peripheral
icmPseP usb = icmNewPSE("usb", usbPer, perAttrs, usbPerIntercept, "modelAttrs");
// connect the USB slave port on the bus and define the address range it occupies
icmConnectPSEBus(usb, bus, "USB", False, 0x80000000, 0x8000013f);
icmConnectPSEBus(usb, bus, "MREAD", True, 0x00000000, 0xffffffff);
icmConnectPSEBus(usb, bus, "MWRITE", True, 0x00000000, 0xffffffff);
USB peripheral instantiation
USB Host Model
The design of the USB 2.0 host peripheral is based on the Enhanced Host Controller Interface standard. The USB host design provides support for periodic transfers. A provision also is made to support asynchronous transfer in the future. The design implements EHCI capability (read only) and operational (read/write) registers starting at offset 0x80000000.
This example makes use of functions intercepted by a specially written intercept library to simulate the USB device. The platform uses Windows dll and USB speakers connected to the host PC’s USB port. The USB device enumeration is performed by the host PC. It is assumed that the USB device/speaker is always attached to the USB host. At the start of simulation, the USB host’s initialization code (userInit function) detects the USB speakers using the UsbDetect()function provided by the UsbDetect.dll. If the USB speakers aren’t detected, it displays a warning message and provides an option to continue simulation using standard PC speakers.
… code …
… code …
bhmMessage("I", "PP_STUBS","sending command for init..\n");
getArg(processor, object, 0, &diagnostics); // read diagnostic level passed as argument
USBDetect(); /* Detect USB speakers */
… code …
USB device detection using USBDetect
The USB driver running on the Diamond core 570T processor configures the USB host for periodic transfer. It also maintains the flow of data from the application to the USB host. The USB host can access the processor-memory space using the read/write bus master port. In order to transfer the data to the USB device/speaker, the USB host reads data from the processor-memory space and sends the buffer pointer and length to the intercept library function using SendDatatoEP_userCB().
static void PeriodicSchedule(void *user)
… code …
retval = semiSendDatatoEP_userCB( (Uns32)Data, TransactionLength);
… code …
Transfer data to USB device
The function call is intercepted by the intercept library. Audio data is then transferred to the Windows dll. The transfer of data from the Tensilica simulation environment to the Windows host involves a change from Tensilica to Windows memory space. This change is accomplished through APIs provided by OVP, vmirtGetProcessorDataDomain() and vmirtReadNByteDomain(). The calling function arguments are retrieved from the stack using the VMI OS support functions provided by OVP. The streaming of data from the USB model to the USB speakers is implemented using WaveLib_LoadBuffer(), part of the usbPlay.dll library. (The mechanism to load Windows dll and calling a function from dll is similar to any Windows application. It is implemented as part of the USB model file.)
static void getArg( vmiProcessorP processor, vmiosObjectP object, Uns32 index, void *result)
… code …
// get the stack
vmiosRegRead(processor, object->sp, &spAddr);
// read argument value
vmirtReadNByteDomain(domain, spAddr+argOffset, result, argSize, 0, True);
Read function arguments
… code …
/ read data from the peripheral memory using the pointer
memDomainP domain = vmirtGetProcessorDataDomain(processor);
vmirtReadNByteDomain(domain, data, DataSrc, sizeof(unsigned int) * len, 0, True);
vmiMessage("I", PREFIX, "Loading data\n");
retval = Load_data( DataSrc, len);
… code …
Transfer of data from Tensilica address space to DLL address space
retval = (WaveLib_LoadBuffer) ( hWavelib, &DataPayload);
Data streaming from intercept library to USB speakers
Audio-Decode Demo Application
The application software consists of the USB host driver and Ogg Vorbis decoder. The software implements a thin layer of the USB driver, which only supports isochronous transfers. The current platform is an intermediate step that initializes the USB host peripheral, controls the USB host-peripheral interrupt, and handles isochronous data transfer. USB stack and protocol functionality including USB enumeration is part of the Windows USB driver. The goal is to move much of the USB stack and protocol functionality onto the Tensilica processor.
if(ov_open(fd, &vf, NULL, 0) < 0)
printf("Input does not appear to be an Ogg bitstream.\n");
… code …
… code …
if (dwBytes == 0)
/* Clean up */
… code …
Ogg Vorbis decoder function usage
The decoder application uses the open-source Ogg Vorbis codec, which is available at www.vorbis.com. The tremor code used in the application is the integer-only version of the Ogg Vorbis decoder. When running on the Tensilica simulation, this decoder consists mainly of two functions. The ov_open function is used to open an Ogg Vorbis encoded audio file and initialize the decoder’s internal structures. Among other variables, it takes as an input the name of the Ogg Vorbis file to be decoded. Once the ov_open call is successful, the ov_read function is called to read the decoded audio. The pointer to the buffer that holds the decoded audio is passed as an input to the ov_read call. On returning from the ov_read function, the input buffer will contain the decoded audio.
For functional verification of the simulation, message printing was facilitated by semi-hosting. Diagnostics were placed in the peripheral model. Using message printing, the correctness of register states and data flow was verified. The register access facility also allowed verification of the drivers’ configuration routines.
The fast simulation speeds and repeatability of the simulation allowed quicker development and debugging of the driver and application than on the actual hardware. Additionally, a GNU debugger was attached to the processor of the OVP platform for driver and application software debugging. The software debugging using the GNU debugger on the simulated hardware provided all of the features of the GNU debugger. It also gave the same look and feel as debugging on the original hardware, but with full control. The development of the simulation models and test application was completed within one month.
This article has shown how a virtual platform can be used to accelerate the development of embedded systems. Open Virtual Platforms technology, which was used to build this virtual platform, is applicable and scales easily to more complex architectures including multicore SoCs. This open, free solution allows embedded-software teams to build and simulate multiprocessor/multi-peripheral platforms. In doing so, it advances these teams toward their goal of higher-quality software under a tighter schedule.
Duncan Graham is senior corporate applications engineer at Imperas Ltd. Graham is an experienced designer and technical support manager for embedded processor systems that encompass system-level design, digital hardware design, and real-time software. He has a bachelor of engineering degree in electrical engineering and electronics from Brunel University in the U.K.
Dhaval Shah is a member of the technical staff at Sibridge Technologies. Shah is an embedded software engineer with wide experience in real-time software design, SoC firmware development, and chip design. He has a master of engineering degree in electrical engineering with a specialization in microprocessor applications from Maharaja Sayajirao University in India.