Simulation and Testboard for Embedded System Design

With software simulation and hardware testboards, you can debug and test code in parallel with hardware development. Michael explains how these techniques were applied to the software-development cycle of an embedded controller.


December 01, 1992
URL:http://www.drdobbs.com/embedded-systems/simulation-and-testboard-for-embedded-sy/184408897

DEC92: SIMULATION AND TESTBOARD FOR EMBEDDED SYSTEM DESIGN

Michael is a software engineer for Advanced NMR Systems Inc., 46 Jonspin Road, Wilmington, MA 01887.


Writing software for an embedded-controller project often puts software engineers in the precarious position of being the last members of the development team to finish their work. Since most embedded-controller systems have a unique configuration, programmers must often wait for hardware to be completed or partially available before beginning real work on debugging and integration. Consequently, the software engineer can become the most visible target for the pressure of getting the product out the door. Also, since software debug occurs on a new target system, there's the additional burden of determining if software failure is due to the code or to the new hardware environment.

Because of these conditions, it is advantageous to take software development as far as possible while still waiting for hardware. This yields the additional benefit of cutting significant time from the development schedule. Through the use of software simulation and hardware testboards, software debugging and testing can occur in parallel with hardware development. This article explains how software simulation and hardware-testboard techniques were applied to a software-development cycle for an embedded controller at Advanced NMR Systems, the company where I work.

Advanced NMR Systems produces the Instascan system, a retrofit device for GE Signa MRI systems. The Instascan system allows the user to create magnetic resonance (MR) images at speeds up to 1/25 of a second. In conventional scanning, this time can range from several seconds to a minute. With decreased imaging time, image-blurring problems due to patient movement, respiration, and coronary motion are virtually eliminated. It is also possible to create real-time "movies" of the heart with the Instascan system.

One component of the Instascan system is the Resonant Power Supply Controller (RPSC), which controls power delivery to the retrofit device, performs waveform generation and analysis, sets numerous scanning parameters, and monitors correct system functioning and patient safety. To accomplish all this, the RPSC communicates with a number of peripheral and logic devices, including a Sun workstation and Data General mainframe. At the heart of the RPSC is a Motorola 68040 microprocessor.

Design and Development

Those of us on the software development team for the RPSC were faced with the task of developing, from the ground up, a sophisticated software-control system for in-house use in six months, with customer delivery shortly thereafter.

Because of its cost and the functionality of its Quickfix debugger (which allows C source-level debugging with the 680x0), we chose to develop with the C Cross-Development tools from Sierra Systems (Oakland, California). While Sierra doesn't provide a compiler specifically for the 68040, minor changes during the installation of the Quickfix debugger let us make full use of the 68020 compiler. The required RPSC software control is complex enough to require a real-time operating system, so we chose the pSOS operating system from Integrated Systems (Santa Clara, California). pSOS met all requirements of the RPSC software specification and provided an interface for the Sierra C compiler.

Our basic approach was to design software that was both modular and layered. Typically, top-level control modules call subroutines that interface with device drivers. Besides generating reusable code, this approach enables software engineers to thoroughly test portions of code before they are combined to create larger software systems. Bugs are easier to locate when software is tested in this manner. This method also facilitates the use of software simulation as an initial test for system software. If top-level control modules, mid-level subroutines, and low-level hardware device drivers are separate entities, introducing software simulators to a system is easy.

The Simulation Process

Software simulation tests are accomplished by adding routines that act in place of actual hardware devices. Hardware drivers interface with the simulation routines exactly as (or as closely as possible to) the device they are designed to drive. Individual software modules are compiled in conjunction with their simulation counterparts, allowing initial verification of correct design and coding of software. The Microsoft C compiler and Codeview debugger provide the environment to evaluate the RPSC software modules on a PC.

A basic design feature in the RPSC software is that all hardware operations make use of the two macros defined in Example 1. In inbyte, the parameter is the address of the hardware register being read--the value is "returned" by the macro. In outbyte, parameter a is the address of the hardware register and parameter b is the value written.

Example 1: Basic RPSC macros.

  #define inbyte(b)     (*((unsigned char *)b))

  #define outbyte(a,b)  (*((unsigned char *)a)=(unsigned char)b)

To create a simulation for routines that use these macros, the macros are replaced by subroutines like those in Example 2 that read from and write to text files. When a software module is compiled with these routines, the module will look to text files for hardware inputs, and any hardware write operations will be recorded in a separate text file.

Example 2: You can replace macros with subroutines like these that read from and write to text files.

  FILE *sim_out;     /* opened at beginning of simulation */
                     /* closed at end.  */

  FILE *sim_in [ONE_FOR_EACH_REGISTER];

  unsigned char inbyte (unsigned char address)
     {
     int invalue;

     fscanf(sim_in [address], "%x", &invalue);
     return(0xFF & invalue);
     }
  void outbyte (unsigned char dest, value);
     {
     fprintf(sim_out, "%x <-- %x\n", dest, value);

     }

Many of the RPS software modules were tested using this approach, including the fault-detection routines. The Fault Monitor task is responsible for monitoring hardware signals for fault events and responding in various ways, depending on the type and severity of the fault. Rigorous initial testing is achieved by creating simulation text files that are read by the Fault Monitor through the inbyte routine just described. The actions of the Fault Monitor are recorded by the outbyte routine for verification.

Another area tested through simulation is operation of a serial device used to send commands to and read status from another board in the system. Commands are transmitted, one bit at a time, by toggling data and control bits in a serial device register. Status is read, one bit at a time, by toggling control and reading data bits in the same serial control register. In this case, the outbyte and inbyte routines require more intelligence, as they must behave as if they are reading from and writing to a serial device. The serial device drivers repeatedly call inbyte and outbyte until a complete command has been sent or a complete status word has been received. By using these simulation routines, both the device drivers and the routines that use them are verified. The pseudocode for the outbyte and inbyte serial simulations is shown in Listing One (page 68).

The RPSC communicates with a Sun workstation through an RS-232 device. Software simulators can test the control routines and device drivers for this interface. Both messages and tables are transmitted and received by the RPSC. The top-level transmit routine calls a subroutine that translates the message or table into a transmittable string. A subroutine then passes the string to the device driver for sending. Similarly, the receive device driver passes the received strings to a subroutine for encoding, and the subroutine passes the encoded message to a top-level receive routine.

The simulation for testing this area involves altering the transmit and receive subroutines to read from and write to text files. For testing the receive software, the receive subroutine reads messages in the form of strings from a file, encodes them, and passes the encoded message to the top-level receive routine. The correct response of the top-level routine is verified. For testing transmission, the top-level send routine is called with a variety of messages and tables. The send subroutine is altered to write the transmittable strings to a file. Further checks are performed by passing the output files created from the transmit simulation to the receive simulation and verifying that the tables are correctly reconstructed in memory. Also, errors are introduced into messages received to verify that incorrect messages are reported and correctly processed.

Using simulations, bugs are easily identified at the module/routine level. After they are fixed and the simulations run correctly, chances are that the software syntax, logic, and routine interfaces are correct. Seventy percent of the modules in the RPSC software were verified using these simulation techniques.

Hardware Testing Techniques

The second phase of RPSC software testing involves a 68000-based hardware testboard (again from Sierra) usually provided for evaluating the use of the compiler/debug environment. Since the Sierra toolset is able to create and debug code for the 68000, and a 68000 version of pSOS is available, the testboard is an excellent substitute for the actual 68040 target board. Quickfix features a fast, parallel download for transferring software from a PC to the target system. Once the RPSC software and pSOS are downloaded to the testboard, full debug of the RPSC software is realized. The above simulations are run again, but this time hardware operations are recorded in RAM instead of in files.

Quickfix is very versatile and provides all the functions that you would expect of a C-level debugger. It allows you to switch between C and assembler and to maintain normal debug operation when in assembler mode. This allows the user to actually step through the pSOS code to observe OS operation. The ability to monitor OS operation was imperative in locating several problems.

The first software problem encountered in using the 68000 testboard was that control never returned from the OS initialization call. The problem lay in setting up the pSOS configuration table. Several entries in the configuration table are pointers to routines that can be executed upon pSOS start up. pSOS documentation states that by filling these locations with 0, no calls are made to startup routines. There is also an entry for a pointer to a jump table used for initializing I/O devices. The documentation does not explicitly state what to do if you are not using I/O devices, so this table location was filled with 0. By tracing the initialization process to the point where the pointer to the jump table was accessed, we saw that the jump was made even though the value was 0. The pSOS initialization process completed correctly after the address of a return instruction was substituted for the 0.

Virtually all the OS calls in the RPSC software can be verified using the testboard. We verified the OS wait function by creating a timer task that used TRAP vectors to run a simulated OS clock. The testboard features a switch for generating a level-1 autovector interrupt. Activation and operation of all tasks driven by external interrupts is tested by modifying the 68000 vector table through the debugger. Using the autovector switch and a combination of TRAPs to simulate external events integrates all software modules. All that remain to be tested are the hardware drivers in a real-time environment.

An additional feature of the testboard is a fully functional 68681 dual asynchronous receiver/transmitter (DUART) chip used by the RPSC control board for communicating with the Sun workstation. The presence of the 68681 on the testboard allows complete verification of DUART initialization and operation software. Upload and download functions are verified by connecting a terminal emulator to the 68681 to act as the Sun workstation.

Conclusion

By the time the actual 68040 board became available, we had gained plenty of experience with the Sierra/pSOS development environment. Thus, we could locate problems more readily than if the 68000 simulation had not been available. One example is a problem that occurs due to an incompatibility between pSOS and the RPSC board design. The software locked up on the first call to the OS wait routine. Again, using the assembler step-through feature, the problem was traced to the idle task executed when no other tasks are active. The pSOS idle task contains an undocumented STOP instruction. Normally the next autovector interrupt will bring the 68040 out of the stopped state. However, due to the interaction between the 68040 and the RPSC interrupt controller, the 68040 remained halted. By inserting another idle task with an endless FOR loop, the STOP instruction can be averted.

Using the techniques described here, most of the RPSC software was debugged before hardware became available. This assured a smooth, rapid integration of hardware and software, upon hardware completion. By using the software simulation and hardware testboard, over one month of debug work was completed before integration was started, allowing the first system to ship 11 months after the RPSC software design was initiated.



_SIMULATION AND TESTBOARD FOR EMBEDDED SYSTEM DESIGN_
by Michael Kutter


[LISTING ONE]


FILE *serial_in,*serial_out;

void outbyte(unsigned char dest,value)
     {
     static long command;
     /* check to make sure dest indicates SERIAL_DEVICE. */
     if (dest != SERIAL_DEVICE)
          {
          printf("Error in Hardware destination address\n");
          return;
          }
     /* reconstruct the command by shifting bits into the */
     /* command variable. */
     if (control bit in value indicates a new command bit
               has been sent)
          {
          command += new input bit in "value";
          command <= 1;
          }
     /* record the command after it is complete */
     if (latch bit in value indicates the command is complete)
          {
          fprintf(serial_out,"serial command: %lx",command);

          command = 0;
          }
     }
unsigned char inbyte(unsigned char source)
     {
     static long status;
     unsigned char return_byte = 0;

     /* check to make sure dest indicates SERIAL_DEVICE. */
     if (source != SERIAL_DEVICE)
          {
          printf("Error in Hardware destination address\n");
          return;
          }
     /* get a new status word */
     if (latch bit in value indicates a new status read)

          fscanf(serial_in,"%lx",&status);
     /* send the status one bit at time, shifting bits  */
     /* out of the status variable */
     if (control bit in status indicates a new statu bit
               has been requested)
          {
          return_byte = status & 0x01;
          status >= 1;
          }
     return(return_byte);
     }



Example 1: Basic RPSC macros

#define inbyte(b)     (*((unsigned char *)b))
#define outbyte(a,b)  (*((unsigned char *)a)=(unsigned char)b)




Example 2: You can replace macros with subroutines like these that read from and write to text files

FILE *sim_out;      /* opened at beginning of simulation */
                    /* closed at end. */
FILE *sim_in[ONE_FOR_EACH_REGISTER];

unsigned char inbyte(unsigned char address)
     {
     int invalue;

     fscanf(sim_in[address],"%x",&invalue);
     return(0xFF & invalue);
     }

void outbyte(unsigned char dest,value);
     {
     fprintf(sim_out,"%x <-- %x\n",dest,value);

     }














Copyright © 1992, Dr. Dobb's Journal

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.