Home -> Using VL2    

  On this page:  
  VL2 documentation:  
This page is an introduction for users of VL2. After following this introduction, you will have used some simple programs to control VL2, and you will be ready to move on to more advanced topics such as the Virtual Lab Hardware Interface.

What you need

The Most Basic Example: Skeleton

The easiest way to use VL2 is to write a program in Python. You can also connect to VL2 using any SSH client; by entering vlab protocol commands, you can control the service directly. Equally, you can use your favourite programming language to implement an interface for the protocol. But the Python approach is easiest because the hard work has been done for you.

The first program is a skeleton that simply connects to the VL2 service. This forms the basis for all of the subsequent programs, which "fill in" detail on line 12:

 1  import vlab
 2  from twisted.internet import reactor, defer
 4  @defer.inlineCallbacks
 5  def Run():
 6      print 'Connecting to the board'
 7      auth = vlab.loadAuthorisation("vluser.key")
 8      vlf = vlab.VlabClientFactory(auth)
 9      reactor.connectTCP(auth.relay_server_name, 22, vlf)
10      vl = yield vlf.getChannel()
11      yield vl.connect("s3esk")
13      vl.disconnect()
14      reactor.stop()
16  if ( __name__ == "__main__" ):
17      reactor.addSystemEventTrigger('after', 'startup', Run)
18      reactor.run()
Line by line, the functions of this program are as follows.

Downloading a bit file

The second program does two things: (1) connect to VL2, then (2) program a bit file onto an FPGA. If you are new to FPGAs, see a general introduction and a Xilinx product page for information specific to Xilinx FPGAs, currently the only type of FPGA device supported by VL2.

 1  import vlab
 2  from twisted.internet import reactor, defer
 4  @defer.inlineCallbacks
 5  def Run():
 6      print 'Loading bit file'
 7      bits = file('test.bit', 'rb').read()
 9      print 'Connecting to the board'
10      auth = vlab.loadAuthorisation("vluser.key")
11      vlf = vlab.VlabClientFactory(auth)
12      reactor.connectTCP(auth.relay_server_name, 22, vlf)
13      vl = yield vlf.getChannel()
14      yield vl.connect("s3esk")
16      print 'Sending bit file'
17      bid = yield vl.sendBitfile(bits)
18      print 'Bid is', bid
19      yield vl.programFPGA(0, bid)
20      print 'Done'
22      vl.disconnect()
23      reactor.stop()
25  if ( __name__ == "__main__" ):
26      reactor.addSystemEventTrigger('after', 'startup', Run)
27      reactor.run()
In this program, the new features are as follows: The programFPGA call on line 19 could be repeated without resending the bit file. However, bit files do not remain in the bit file buffers indefinitely. Typically, there are only about ten bit file buffers per board server, and sending a new bit file will cause the oldest bit file to be replaced. If this happens, its bid becomes invalid, and a call to programFPGA will raise an exception.

Using a UART

The third program connects to a UART after programming. A UART is a hardware device that sends and receives data over a serial line. The serial protocol is RS232, always with 8 bits, one stop bit, and no parity. The baud rate is selectable.

Almost all computers can use RS232, and any FPGA design can use RS232 with the addition of a small UART of its own. We could have implemented an ad-hoc protocol for communication between the FPGA design and the virtual lab, but that would be silly when a perfectly adequate serial protocol has been in use for decades. The virtual lab UART is not a high bandwidth connection. RS232 is not fast. But it is perfectly adequate for debugging designs.

 1  import vlab
 2  from twisted.internet import reactor, defer
 4  MESSAGE = 'Hello World'
 6  @defer.inlineCallbacks
 7  def Run():
 8      print 'Connecting to board and programming FPGA'
 9      bits = file("test.bit", 'rb').read()
10      auth = vlab.loadAuthorisation("vluser.key")
11      vlf = vlab.VlabClientFactory(auth)
12      reactor.connectTCP(auth.relay_server_name, 22, vlf)
13      vl = yield vlf.getChannel()
14      yield vl.connect("s3esk")
15      bid = yield vl.sendBitfile(bits)
16      yield vl.programFPGA(0, bid)
18      print 'Opening UART'
19      uart = vlab.VlabUARTProtocol()
20      yield vl.openUART(0, uart)
22      print 'Sending a message'
23      uart.write(MESSAGE)
25      print 'Waiting for reply'
26      data = yield uart.read(len(MESSAGE))
28      print 'Reply is:', repr(data)
30      vl.disconnect()
31      reactor.stop()
33  if ( __name__ == "__main__" ):
34      reactor.addSystemEventTrigger('after', 'startup', Run)
35      reactor.run()
In this program, the notable new feature is the use of vlab.VlabUARTProtocol() to create a Twisted Protocol object, which is passed to openUART. The Protocol represents the UART. You can give any Twisted Protocol to openUART. For some applications it may be best to write your own. But vlab.VlabUARTProtocol() already has the ability to wait for N bytes to be received, as in data = yield uart.read(N). You can use the read and write methods to control your FPGA design from Python.

Using a UART, Interactively

Sometimes you want to interact with the design on the FPGA. One way to do that is to implement a complete application, like the EMS client, which provides whatever features you actually need for whatever it is you are doing. Of course there is no "one size fits all" solution. But many FPGA designs include CPUs, and CPUs tend to run interactive programs.

For these, you might want to interact with the FPGA design via a UART. The following example program connects to a StrongARM-based embedded system named CATS. It toggles a relay to operate the reset switch, and then opens an interactive terminal session. Once the terminal session is running, any output from CATS is echoed to the screen. Any keys pressed by the user are sent to CATS. This is not an FPGA system, hence no bit file is sent. If it was, the FPGA programming step would precede openUART as usual.

 1  import vlab
 2  from twisted.internet import reactor, defer
 3  from vlab import terminal
 5  @defer.inlineCallbacks
 6  def Run():
 7      print 'Connecting to CATS board'
 8      auth = vlab.loadAuthorisation("vluser.key")
 9      vlf = vlab.VlabClientFactory(auth)
10      reactor.connectTCP(auth.relay_server_name, 22, vlf)
11      vl = yield vlf.getChannel()
12      yield vl.connect("cats")
13      yield vl.setUART(0, 115200)
15      print 'Pressing reset switch'
16      yield vl.setRelay(1, 1)
17      yield vl.setRelay(1, 0)
18      yield vl.setRelay(1, 1)
20      print 'Opening UART'
21      uart = terminal.DumbTerminal()
22      terminal.setTransport(uart)
23      yield vl.openUART(0, uart)
25  if ( __name__ == "__main__" ):
26      reactor.addSystemEventTrigger('after', 'startup', Run)
27      reactor.run()

DumbTerminal is a Python class. It can be extended to implement more advanced features such as an escape character to exit the program (by extending the write() method).

Using SOCKS to get around firewalls

Your virtual lab relay server might be behind a firewall, preventing connections from the Internet. For example, at York, the virtual lab server is only reachable within the Computer Science Department. In this situation, you can use a SOCKS proxy to forward connections. VlabClientFactory objects are created slightly differently:

    vlf = vlab.VlabClientFactory(auth_data=auth,
    reactor.connectTCP('socksserver.example.com', 1080, vlf)
    vl = yield vlf.getChannel()
In the example, the SOCKS server is socksserver.example.com and the port is 1080. The virtual lab client connects to the SOCKS server and tells it to forward the connection to the virtual lab relay server. The most common usage of this feature is probably in conjunction with the "-D" option of an SSH client.

A Complete Program

The EMS client is a complete virtual lab program with a GUI.

  Copyright (C) Jack Whitham 1997-2011