JACK WHITHAM    
       
    Home -> vlabifhw    

   
 
  On this page:  
 
   
 
  VL2 documentation:  
 
In some applications, it is sufficient to have a single UART connection to the hardware within an FPGA, e.g. as a serial console. But in many applications, more than one "channel" is required, allowing multiple independent serial connections to exist at the same time. For example, a CPU core might have a debug interface and a UART; a developer might want to write data to the UART while using the debug interface. Or a Handel C design might want to print debug messages while exchanging data with a program on a PC. For these cases, a "concentrator" is needed to multiplex multiple independent channels into a single connection.

The virtual lab interface hardware (vlabifhw) provides this concentrator service, allowing software to communicate with multiple devices inside an FPGA. The software component, vlabif, has its own documentation. You can get vlabifhw and vlabif as a zip archive from the download page.

vlabifhw is completely independent of VL2. The hardware component (vlabifhw) can be connected to a VL2 board server, or any computer with an RS232 port. The software component (vlabif) can use the vlab module to communicate via a VL2 board server, or the pyserial module to communicate via a local serial port.

Usage

vlabifhw supports up to 14 user-defined bi-directional channels for 8 bit data:
Typical usage
A bi-directional channel represented in hardware The same channel represented in software
Example 1Example 2
in_channel_data : in std_logic_vector(7 downto 0);
in_channel_wr : in std_logic_vector(0 downto 0);
in_channel_rdy : out std_logic_vector(0 downto 0);
out_channel_data : out std_logic_vector(7 downto 0);
out_channel_wr : out std_logic_vector(0 downto 0);
out_channel_rdy : in std_logic_vector(0 downto 0);
1 auth = vlab.loadAuthorisation("vluser.key")
2 vlf = vlab.VlabClientFactory(auth)
3 reactor.connectTCP(auth.relay_server_name, 22, vlf)
4 yield vlf.getChannel()
5
6 ip = vlabif.VlabInterfaceProtocol()
7 yield vl.openUART(0, ip)
8 yield ip.start()
9
10 # create channel interface:
11 chan = vlabif.SimpleDriver()
12 # (or other twisted.internet.protocol.Protocol)
13 ip.openChannel(1, chan)
14
15 chan.write("send bytes")
16 reply = yield chan.wait(5)
1 ip = vlabif.VlabInterfaceProtocol()
2
3 serialport.SerialPort(ip, "/dev/ttyS0",
4     reactor=reactor, baudrate=115200)
5 yield ip.start()
6
7 # create channel interface:
8 chan = vlabif.SimpleDriver()
9 # (or other twisted.internet.protocol.Protocol)
10 ip.openChannel(1, chan)
11
12 chan.write("send bytes")
13 reply = yield chan.wait(5)
VHDL interface of vlabifhw Python interface of vlabif using a VL2 connection with authorisation file vluser.key Python interface of vlabif using local serial port /dev/ttyS0.
Data written to "chan" will appear on "out_channel". On each positive-going clock edge, "out_channel_rdy" is sampled. If it is high, and if data is waiting, then the next byte of data is placed on "out_channel_data" and "out_channel_wr" is asserted high for one clock cycle. Therefore, a typical usage pattern is as follows:
    process ( clk ) is
    begin
        if ( clk'event )
        and ( clk = '1' )
        then
            if ( out_channel_wr = '1' ) and ( ready = '1' )
            then
                do_something_with ( out_channel_data ) ;
            end if ;
        end if ;
    end process ;
    out_channel_rdy <= ready ;
In this usage pattern, "do_something_with" will be activated on every clock cycle where a new byte is available. If the program shown above is being executed, it will be activated ten times for each byte in the string "send bytes".

"in_channel" has the same interface. "in_channel_wr" may be asserted when "in_channel_rdy" is high; if this is done, then the byte on "in_channel_data" is accepted as input. A typical usage pattern would be:

    process ( clk ) is
    begin
        if ( clk'event )
        and ( clk = '1' )
        then
            in_channel_wr <= '0' ;
            if ( in_channel_rdy = '1' )
            then
                in_channel_data <= produce_byte () ;
                in_channel_wr <= '1' ;
            end if ;
        end if ;
    end process ;

Synthesising vlabifhw

To synthesise vlabifhw, add the following VHDL files in the vlabifhw directory to your hardware project:
Note: If you are using a Xilinx FPGA, you can remove fifo.vhd and replace it with fifo_xilinx.vhd. If you do this, you should also add fifo_kc.vhd and bbfifo_16x8.vhd to the project. bbfifo_16x8 is a Xilinx-optimised FIFO implementation by Ken Chapman, originally distributed with the Picoblaze CPU. The file is also available from here. It is not distributed with vlabifhw for licensing reasons.
After adding the vlabifhw files, add the vlabifhw component to one of your own VHDL files. You must connect the following inputs and outputs: There are five generic parameters to be set: There are a number of optional input connections. The first set are used for channels:
in_channel_data  : in std_logic_vector(X downto 0);
in_channel_wr    : in std_logic_vector(Y downto 0);
in_channel_rdy   : out std_logic_vector(Y downto 0);
out_channel_data : out std_logic_vector(X downto 0);
out_channel_wr   : out std_logic_vector(Y downto 0);
out_channel_rdy  : in std_logic_vector(Y downto 0);
X is calculated as ( 8 * ext_channels ) - 1, Y is calculated as ext_channels - 1. In this way, the size of these vectors is set to match ext_channels. Let Z be a channel number from 1 to ext_channels. Here is how the bits of in/out_channel are related to channel numbers:
channel numberZ
_data vector( ( Z * 8 ) - 1 downto ( Z * 8 ) - 8
_wr vector( Z - 1 )
_rdy vector( Z - 1 )
software: openChannel() parameterZ
There are a number of debugging signals, which are directly connected to the debugging device:
debug_clock     : out std_logic;
debug_reset     : out std_logic;
breakpoint      : in std_logic;

dc_control      : out DC_Control_Wires;
dc_out          : out std_logic;
dc_in           : in std_logic
These are documented elsewhere.

There are three other connections that you should be aware of, even if you do not use them:

Skeleton

It is likely that you will only want to use some of the functionality of vlabifhw in an application. A minimal instantiation of the component (which does nothing other than responding to vlabif) is as follows:
    vlhw : entity vlabifhw
        generic map (
            ext_channels => 1 ,
            fifo_depth => 1,
            clock_freq => clock_freq )
        port map (
            -- External hardware connections
            clk => clk,
            reset => '0',
            hw_tx => hw_tx,
            hw_rx => hw_rx,

            -- Internal connections: these are not used in this example.
            out_channel_data => open,
            out_channel_wr => open,
            out_channel_rdy => "1",

            in_channel_data => x"00",
            in_channel_wr => "0",
            in_channel_rdy => open,

            -- Activation signal: not used
            active => open,

            -- Controls for device under test: also not used
            debug_clock => open,
            debug_reset => open,
            breakpoint => '0',

            dc_control => open,
            dc_out => open,
            dc_in => '0'
        );

Before and after activation

Before the vlabif start() method is executed, the vlabifhw component connects channel 1 to the external UART. It relays data between them. This allows you to synthesise vlabifhw into every design regardless of whether it is used or not - a built-in test and debugging feature. You can use the UART directly (without activating vlabifhw) or indirectly through vlabifhw.

start() sends an activation escape code that turns the vlabifhw features on; this activation code must begin within the first 7 bytes that are sent, or it will be ignored and relayed normally. This activation code is documented in the vlabif protocol documentation.

Alternate Interface: Multiple Clock Domains

The vlabifhw component expects all of its channels to use the same clock input: the "clk" input given to vlabifhw. In some applications, this may not be possible. In these cases, the "vlabifhw_cn" component should be used instead, as it allows each channel to have its own clock. This is done by adding an extra layer of registers to the vlabifhw component, using a handshake protocol to move data between clock domains.


       
  Copyright (C) Jack Whitham 1997-2011