/*****************************************************************************
 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
