Cadence.com will be under maintenance from Friday, Oct. 3rd at 6pm (PST) thru Sunday, Oct 5th at 11pm (PST).
Cadence.com login, registration, community posting and commenting functionalities will be disabled.
Home > Community > Blogs > System Design and Verification > uart use number 1 connecting to an interactive terminal
 
Login with a Cadence account.
Not a member yet?
Create a permanent login account to make interactions with Cadence more convenient.

Register | Membership benefits
Get email delivery of the System Design and Verification blog (individual posts).
 

Email

* Required Fields

Recipients email * (separate multiple addresses with commas)

Your name *

Your email *

Message *

Contact Us

* Required Fields
First Name *

Last Name *

Email *

Company / Institution *

Comments: *

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

Comments(2)Filed under: System Design and Verification, SystemC, virtual platforms, virtual prototypes, System Development Suite, Virtual System Platform, UART, Embecosm, xterm

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

 

Comments(2)

By Jeremy Bennett on August 19, 2011
Hi Jason,
Nice description and glad you found the Embecosm article useful.
We've recently been simulating Ethernet using TUN/TAP, allowing you to connect to models via FTP/telnet as though they are on a real network. I haven't written it up yet, but that is very relevant to your next article.
Best wishes,
Jeremy Bennett
--
Tel:      +44 (1590) 610184
Cell:     +44 (7970) 676050
SkypeID: jeremybennett
Email:   jeremy.bennett@embecosm.com
Web:     www.embecosm.com

By Anup on December 30, 2012
HI Jason
Thank you for this article .
It helped me to fix the random xterm freeze issues while simulation .
Thanks
Anup

Leave a Comment


Name
E-mail (will not be published)
Comment
 I have read and agree to the Terms of use and Community Guidelines.
Community Guidelines
The Cadence Design Communities support Cadence users and technologists interacting to exchange ideas, news, technical information, and best practices to solve problems and get the most from Cadence technology. The community is open to everyone, and to provide the most value, we require participants to follow our Community Guidelines that facilitate a quality exchange of ideas and information. By accessing, contributing, using or downloading any materials from the site, you agree to be bound by the full Community Guidelines.