Computer Laboratory

Bluepsec Examples

Avalon Streaming Interface

Overview

This package provides an Avalon Streaming interface which is compliant (though I don't make any guarantees!) with Altera's Avalon interconnect system used by their SOPC Builder tool. It effectively allows Get and Put interfaces within Bluespec to be passed to the SOPC Builder system allowing these communication channels to be hooked together using the SOPC Builder GUI environment. Flow-control is preserved. Some examples are also provided at the end of this page.

Avalon Streaming Interface Code

/*****************************************************************************
 AvalonStreaming
 ===============
 Simon Moore, May 2010
 
 This library provides Bluespec wrappers for Altera's Avalon Streaming
 interface.

 * Names - SOPC Builder expects the following names to be used for streaming
   interfaces (i.e. these are the names you should use in the top-level
   interface):
    * aso - Avalon-ST source
    * asi - Avalon-ST sink
  
 *****************************************************************************/

package AvalonStreaming;

import GetPut::*;
import FIFOF::*;

/*****************************************************************************
 Source Stream
 *****************************************************************************/

// Avalon-ST source physical interface.  Note that names of modules
// match SOPC's expectations.
(* always_ready, always_enabled *)
interface AvalonStreamSourcePhysicalIfc#(numeric type dataT_width);
   method Bit#(dataT_width) stream_out_data;
   method Bool stream_out_valid;
   method Action stream_out(Bool ready);
endinterface

interface AvalonStreamSourceVerboseIfc#(type dataT, numeric type dataT_width);
   interface Put#(dataT) tx;
   interface AvalonStreamSourcePhysicalIfc#(dataT_width) physical;
endinterface

typedef AvalonStreamSourceVerboseIfc#(dataT,SizeOf#(dataT)) AvalonStreamSourceIfc#(type dataT);

module mkPut2AvalonStreamSource(AvalonStreamSourceVerboseIfc#(dataT,dataT_width))
   provisos(Bits#(dataT,dataT_width));
   
   Wire#(Maybe#(Bit#(dataT_width))) data_dw <- mkDWire(tagged Invalid);
   Wire#(Bool) ready_w <- mkBypassWire;
   
   interface Put tx;
      method Action put(dataT d) if(ready_w);
	 data_dw <= tagged Valid pack(d);
      endmethod
   endinterface

   interface AvalonStreamSourcePhysicalIfc physical;
      method Bit#(dataT_width) stream_out_data;
	 return fromMaybe(0,data_dw);
      endmethod
      method Bool stream_out_valid;
	 return isValid(data_dw);
      endmethod
      method Action stream_out(Bool ready);
	 ready_w <= ready;
      endmethod
   endinterface
endmodule


/*****************************************************************************
 Sink Stream
 *****************************************************************************/

// Avalon-ST sink physical interface.  Note that names of modules
// match SOPC's expectations.

(* always_ready, always_enabled *)
interface AvalonStreamSinkPhysicalIfc#(type dataT_width);
   method Action stream_in(Bit#(dataT_width) data, Bool valid);
   method Bool stream_in_ready;
endinterface

interface AvalonStreamSinkVerboseIfc#(type dataT, numeric type dataT_width);
   interface Get#(dataT) rx;
   interface AvalonStreamSinkPhysicalIfc#(dataT_width) physical;
endinterface

typedef AvalonStreamSinkVerboseIfc#(dataT,SizeOf#(dataT)) AvalonStreamSinkIfc#(type dataT);


module mkAvalonStreamSink2Get(AvalonStreamSinkVerboseIfc#(dataT,dataT_width))
   provisos(Bits#(dataT,dataT_width));
   
   FIFOF#(dataT) f <- mkLFIFOF;
   Wire#(Maybe#(dataT)) d_dw <- mkDWire(tagged Invalid);
   
   rule push_data_into_fifo (isValid(d_dw));
      f.enq(fromMaybe(?,d_dw));
   endrule
   
   interface Get rx = toGet(f);

   interface AvalonStreamSinkPhysicalIfc physical;
      // method to receive data.  Note that the data should be held
      // until stream_in_ready is True, i.e. there is room in the internal
      // FIFO - f - so we should never loose data from our d_dw DWire
      method Action stream_in(Bit#(dataT_width) data, Bool valid);
	 if(valid)
	    d_dw <= tagged Valid unpack(data);
      endmethod
      method Bool stream_in_ready;
	 return f.notFull;
      endmethod
   endinterface
endmodule


endpackage

Link to the AvalonStreaming.bsv source

Example Test Code

/*****************************************************************************
 Test AvalonStreaming
 ====================
 Simon Moore, May 2010
 
 This produces three simple Avalon Stream devices to test the AvalonStreaming
 library:
 
  * simple counter source
  * a stream doubler (i.e. reads from input stream and outputs the input*2)
  * a stream jitter inserter (i.e. randomly pauses stream.  Useful to test
    that back pressure is working correctly
 
 These devices can be imported into SOPC builder simply and only require that
 the data width be set to 32-bits.
 *****************************************************************************/

import GetPut::*;
import FIFO::*;
import AvalonStreaming::*;
import Clocks::*;
import LFSR::*;

typedef UInt#(32) TestT;

interface OneSourceIfc;
   interface AvalonStreamSourcePhysicalIfc#(SizeOf#(TestT)) aso;
endinterface

interface SinkAndSourceIfc;
   interface AvalonStreamSinkPhysicalIfc#(SizeOf#(TestT)) asi;
   interface AvalonStreamSourcePhysicalIfc#(SizeOf#(TestT)) aso;
endinterface


(* synthesize,
 reset_prefix = "csi_clockreset_reset_n",
 clock_prefix = "csi_clockreset_clk" *)
module mkCountingAvalonSource(OneSourceIfc);
   
   Reg#(TestT) ctr <- mkReg(0);
   
   AvalonStreamSourceIfc#(TestT) src <- mkPut2AvalonStreamSource;
   
   rule inc_ctr_put;
      src.tx.put(ctr);
      ctr <= ctr+1;
   endrule

   interface aso = src.physical;
endmodule


(* synthesize,
 reset_prefix = "csi_clockreset_reset_n",
 clock_prefix = "csi_clockreset_clk" *)
module mkDoubleAvalonStream(SinkAndSourceIfc);
   
   AvalonStreamSinkIfc#(TestT) rx <- mkAvalonStreamSink2Get;
   AvalonStreamSourceIfc#(TestT) tx <- mkPut2AvalonStreamSource;
   
   rule double;
      let d <- rx.rx.get();
      tx.tx.put(d<<1);
   endrule

   interface asi = rx.physical;
   interface aso = tx.physical;
   
endmodule


(* synthesize,
 reset_prefix = "csi_clockreset_reset_n",
 clock_prefix = "csi_clockreset_clk" *)
module mkJitterAvalonStream(SinkAndSourceIfc);
   
   LFSR#(Bit#(32)) random <- mkLFSR_32;
   
   let stop = (random.value & 32'hf) == 0;
   
   AvalonStreamSinkIfc#(TestT) rx <- mkAvalonStreamSink2Get;
   AvalonStreamSourceIfc#(TestT) tx <- mkPut2AvalonStreamSource;
   
   rule forward (!stop);
      let d <- rx.rx.get();
      tx.tx.put(d);
   endrule
   
   rule next_random;
      random.next;
   endrule

   interface asi = rx.physical;
   interface aso = tx.physical;
   
endmodule

Link to the TestAvalonST.bsv source