• Skip to main content
  • Skip to search
  • Skip to footer
Cadence Home
  • This search text may be transcribed, used, stored, or accessed by our third-party service providers per our Cookie Policy and Privacy Policy.

  1. Blogs
  2. Verification
  3. Virtual Platform UART Use Number 1: Connecting to an Interactive…
jasona
jasona

Community Member

Blog Activity
Options
  • Subscribe by email
  • More
  • Cancel
Virtual System Platform
virtual platforms
Embecosm
virtual prototypes
UART
System Design and Verification
System Development Suite
xterm
SystemC

Virtual Platform UART Use Number 1: Connecting to an Interactive Terminal

18 Aug 2011 • 8 minute read

Welcome to the first example of using a UART in a Virtual Platform. For those just joining, I outlined a list of four UART uses in my previous introduction.

One of the most common ways to use a UART in a Virtual Platform is to connect to a terminal and use it as an input and output device. When working with real hardware it's common to connect a serial cable and use various terminal emulation programs to connect to an embedded system. Commonly used programs for Windows are HyperTerminal or PuTTY. For Linux, programs like minicom are used. There are many examples of instructions on how to connect the serial cable, but for reference I found this article to be a representative example.

In the Virtual Platform domain using any of these terminal emulators is possible, but one of the easiest things to use is the plain old xterm. Today, I will talk about how to use an xterm in slave mode to connect to a UART model in a Virtual Platform. Pretty much everybody has used an xterm to get to a shell prompt on a Unix system, however, not many people know there is a mode of the xterm called slave mode. Slave mode can be used to connect the rx and tx data as shown on the diagram shown in the introduction.

When using slave mode a new xterm does not start a shell, but instead connects to an already running program. The main page for xterm has somewhat cryptic information that looks promising, but is not all that clear. I like how it says that the -S option is "sometimes used in specialized applications." I guess that's what we are doing.

Here is the information for the -S switch for xterm:

-Sccn

This option allows xterm to be used as an input and output channel for an existing program and is sometimes used in specialized applications. The option value specifies the last few letters of the name of a pseudo-terminal to use in slave mode, plus the number of the inherited file descriptor. If the option contains a ''/'' character, that delimits the characters used for the pseudo-terminal name from the file descriptor. Otherwise, exactly two characters are used from the option for the pseudo-terminal name, the remainder is the file descriptor. Examples:

-S123/45
-Sab34

Note that xterm does not close any file descriptor which it did not open for its own use. It is possible (though probably not portable) to have an application which passes an open file descriptor down to xterm past the initialization or the -S option to a process running in the xterm.

Let's see how xterm -S can be used to add an xterm connection to a SystemC UART model.

  • Create a SystemC model, let's call it a "terminal model", with a thread to launch the xterm and listen for the user to type characters, and another thread to listen for the UART to send characters and then forward these out to the xterm so they appear on the screen.
  • Launch the xterm in slave mode using a fork/exec sequence. The xterm is the child process and the simulator is the parent.
  • Setup signal handling in the parent process to wait for xterm input. It's also possible (and maybe useful) to poll for the input from the xterm (described later).
  • Use the SystemC thread that was setup to process input from the xterm to read the characters and send them to the UART.
  • Use the other SystemC thread that was setup to process output to wait for characters from the UART and write them to the xterm.

Using words like send and receive can get confusing in this setup because they depend on the perspective of the describer. The UART sending characters (send) are received by the terminal model (receive) and then forwarded (send) to the xterm. A picture of the flow is shown below.

 

 

The good news about this description is that there is already a good example available in the form of an application note from Embecosm. The section that is relavent is section 7.2 and following. There is actual code that can be downloaded and used which contains a terminal model in SystemC that uses an xterm in slave mode for input/output. If you download the code look for the files TermSC.h and TermSC.cpp. This is a great place to start learning. Thanks to Embecosm for making it available.

Rather than re-explaining everything in the Embecosm app note, I'll focus on the parts that are interesting for me or places where modifications are useful in the context of the Cadence Virtual System Platform.

Pseudo-terminal Setup

One interesting thing to study in the use of xterm -S is how to open the correct file descriptors to talk to the xterm once it is running. Before the xterm is launched you will see a system call to open with /dev/ptmx as the argument. A good place to start to understand this is the man page for ptmx. Other system calls like grantpt and ptsname are used to connect to the pseudo-terminal interface.

The final result is the handle to be used for the read and write system calls to send and receive characters correctly.

If I do a ps command after a simulation is started (this one has 2 UARTs and terminals) I see the arguments provided to the xterm for slave mode.

The -S argument has the last 2 characters of the psedu-terminal name followed by the slash and then the file descriptor used to access the terminal.

Using a Different Signal Instead of SIGIO

Another interesting thing about the terminal model is that it uses a signal (SIGIO) to catch terminal input. This way no activity is triggered until some input is received. Because signals work at the process level it's not clear which xterm has the input ready if there are multiple that were launched by the simulation process. To solve this select is used to match the right instance of the model with the received signal.

One thing I learned about signals is that they can be hard to deal with if other places in the application are already using the same signals. The usual solution is to chain the signal handlers so that all code using the same signal gets a chance to process it, but in reality it's not always so easy. In this case, I found ncsim and simvision use SIGIO already. Rather than get in way of this I changed to SIGUSR2 instead to catch the xterm input and it works much better.

Another thing to be aware of is when debugging SystemC models gdb will stop on receipt of certain signals (such as SIGUSR2) so I use a .gdbinit file to specify a command to run at startup so gdb will not stop when signals are generated by the user typing in the xterm. The gdb command for this is:

handle SIGUSR2 nostop noprint

Polling for I/O Instead of Using a Signal

Using asynchronous I/O for the terminal input sounds very efficient, but I found it can cause some problems. I learned from experience that a complex application like ncsim may not be in a good state to receive asynchronous signals all of time. The result is strange crashes if the signal occurs at the wrong time. I'm sure there is a good explanation for it (or maybe it's a real bug), but I didn't try to dig to the bottom of this trouble. I found the best solution is to wait for the first signal to occur and then switch to a polling mode from the terminal model to avoid receiving signals at inopportune times and causing crashes. For interactive usage the polling interval can be tuned so the user doesn't notice any performance difference.

The original code to read a character from the terminal looks like this:

void
TermSC::xtermThread()
{
  while( true ) {
    wait( *ioEvent );       // Wait for some I/O on the terminal
    tx.write( xtermRead()); // Get the char and sent it on
  }
}

The polling version looks like this:

void
term::xtermThread()
{
  unsigned char c;

  // Wait for the first I/O on the terminal
  wait(*ioEvent);

  // Switch to pull mode: pulling I/O on the terminal
  while (true) {

    wait(INPUT_POLL_TIME_INTERVAL, INPUT_POLL_TIME_UNIT);

    // Get the char and send it on to the UART
    // xtermRead() performs non-blocking real. It returns 0 if there is no input char.
    c = xtermRead();
    if (c != 0) {
      tx.write(c);
    }
  }
}

Setting Terminal Attributes

Another area of system programming is setting the terminal attributes to make the terminal behave correctly. I found that additional attributes were needed to have a friendly interactive terminal. Without these the characters do not echo as they are typed (which makes it almost impossible to use).

I found there are so many options it can be confusing. One good reference I found is located here.

I found these settings by looking at various examples and they work well for me. Depending on your setup you may get different behavior. The variable tty is declared as:

struct termios tty;

 

 

Adding scroll bars to the xterm

Another easy thing to experiment with is to add more options to the xterm such as scroll bars so you can see more information. This can easily be done by adding arguments to the xterm command line. Add another element to the argv array to add -sb to the xterm launch:

argv[2] = (char *)("-sb");
argv[3] = NULL;

Conclusion

Studying a terminal model which uses an xterm in slave mode is a great example of Linux system programming. We have seen many interesting system calls. Understanding things like fork/exec, pseudo-terminal configuration, signal handling, and read/write system calls are all good things for anybody working on Virtual Platform modeling to learn.

Next time I'll cover a different way to provide a similar interactive connection, but instead of a pseudo-terminal interface the telnet protocol will be used. With telnet the user can connect to the simulated system from any other machine on the network.

Jason Andrews

 

© 2025 Cadence Design Systems, Inc. All Rights Reserved.

  • Terms of Use
  • Privacy
  • Cookie Policy
  • US Trademarks
  • Do Not Sell or Share My Personal Information