OpenCores
URL https://opencores.org/ocsvn/qaz_libs/qaz_libs/trunk

Subversion Repositories qaz_libs

[/] [qaz_libs/] [trunk/] [axi4_stream_lib/] [src/] [axis_downsizer.sv] - Rev 38

Go to most recent revision | Compare with Previous | Blame | View Log

//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2015 Authors and OPENCORES.ORG                 ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source is distributed in the hope that it will be       ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
//// PURPOSE.  See the GNU Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////

module
  axis_downsizer
  #(
    N,              // data bus width in bytes
    I = 1,          // TID width
    D = 1,          // TDEST width
    U,              // TUSER width
    S,              // tdata size divisor
    USE_TSTRB = 0,  //  set to 1 to enable, 0 to disable
    USE_TKEEP = 0,  //  set to 1 to enable, 0 to disable
    BYTES_PER_TUSER //  bytes per tuser bit. Set to 0 for transfer based.
  )
  (
    axis_if axis_in,
    axis_if axis_out,
    input   aclk,
    input   aresetn
  );

// --------------------------------------------------------------------
// synthesis translate_off
  initial
  begin
    a_divisor: assert(S > 1) else $fatal;
    a_tdata_mod: assert(N % S == 0) else $fatal;
    a_tstrb_unsuported: assert(USE_TSTRB == 0) else $fatal;
    a_tkeep_unsuported: assert(USE_TKEEP == 0) else $fatal;
    a_bytes_per_tuser: assert((BYTES_PER_TUSER == 0) | (N % BYTES_PER_TUSER == 0)) else $fatal;
    a_tuser: assert((BYTES_PER_TUSER == 0) | (U % S == 0)) else $fatal;
  end
// synthesis translate_on
// --------------------------------------------------------------------


  // --------------------------------------------------------------------
  //
  localparam M_A = $clog2(S);
  localparam M_D = 2 ** M_A;
  localparam M_NW = (N*8)/ S;
  localparam M_UW = U / S;


  // --------------------------------------------------------------------
  //
  localparam U_OUT = (BYTES_PER_TUSER == 0) ? U : U / (N / BYTES_PER_TUSER);
  axis_if #(.N(N/S), .U(U_OUT)) axis_downsizer_bus(.*);


  // --------------------------------------------------------------------
  //
  wire almost_last_word;


  //---------------------------------------------------
  //  state machine binary definitions
  enum reg [2:0]
    {
      GET_WORD_IN   = 3'b001,
      MUX_WORD_OUT  = 3'b010,
      LAST_WORD_OUT = 3'b100
    } state, next_state;


  //---------------------------------------------------
  //  state machine flop
  always_ff @(posedge aclk)
    if(~aresetn)
      state <= GET_WORD_IN;
    else
      state <= next_state;


  //---------------------------------------------------
  //  state machine
  always_comb
    case(state)
      GET_WORD_IN:          if(axis_in.tvalid)
                              next_state <= MUX_WORD_OUT;
                            else
                              next_state <= GET_WORD_IN;

      MUX_WORD_OUT:         if(almost_last_word & axis_downsizer_bus.tready)
                              next_state <= LAST_WORD_OUT;
                            else
                              next_state <= MUX_WORD_OUT;

      LAST_WORD_OUT:        if(~axis_downsizer_bus.tready)
                              next_state <= LAST_WORD_OUT;
                            else if(axis_in.tvalid)
                              next_state <= MUX_WORD_OUT;
                            else
                              next_state <= GET_WORD_IN;

      default:              next_state <= GET_WORD_IN;

    endcase


  // --------------------------------------------------------------------
  //
  reg [(8*N)-1:0] tdata_r;
  reg [I-1:0]     tid_r;
  reg [D-1:0]     tdest_r;
  reg             tlast_r;
  reg [U-1:0]     tuser_r;

  always_ff @(posedge aclk)
    if(axis_in.tvalid & axis_in.tready)
    begin
      tdata_r <= axis_in.tdata;
      tid_r   <= axis_in.tid;
      tdest_r <= axis_in.tdest;
      tlast_r <= axis_in.tlast;   // packet width % S == 0 else tlast becomes invalid
      tuser_r <= axis_in.tuser;
    end


  // --------------------------------------------------------------------
  //
  reg [M_A-1:0] select;
  assign almost_last_word = (select == S - 2);

  always_ff @(posedge aclk)
    if(~aresetn | (state == GET_WORD_IN))
      select <= 0;
    else if(axis_downsizer_bus.tvalid & axis_downsizer_bus.tready)
      select <= select + 1;


  // --------------------------------------------------------------------
  //
  wire [M_NW-1:0] mux_in_tdata [M_D-1:0];
  wire [M_NW-1:0] mux_out_tdata;

  recursive_mux #(.A(M_A), .W(M_NW))
    tdata_mux_i(.data_in(mux_in_tdata), .data_out(mux_out_tdata), .*);


  // --------------------------------------------------------------------
  //
  genvar j;
  
  generate
    for(j = 0; j < M_D; j++)
      begin : tdata_gen
        assign mux_in_tdata[j] = tdata_r[j*M_NW +: M_NW];
      end
  endgenerate


  // --------------------------------------------------------------------
  //
  generate
    begin : tuser_gen
      if(BYTES_PER_TUSER != 0)
      begin : tuser_tuser_0_gen
        wire [M_UW-1:0] mux_in_tuser [M_D-1:0];

        recursive_mux #(.A(M_A), .W(M_UW))
          tuser_mux_i(.data_in(mux_in_tuser), .data_out(axis_downsizer_bus.tuser), .*);

        for(j = 0; j < M_D; j++)
        begin : tuser_j_gen
          assign mux_in_tuser[j] = tuser_r[j*M_UW +: M_UW] & {M_UW{axis_downsizer_bus.tvalid}};
        end
      end
      else
      begin : tuser_tuser_gen
        assign axis_downsizer_bus.tuser = tuser_r & {U{axis_downsizer_bus.tvalid}};
      end
    end
  endgenerate


  // --------------------------------------------------------------------
  //
  assign axis_in.tready   = (state == GET_WORD_IN) |
                            ((state == LAST_WORD_OUT) & (next_state == MUX_WORD_OUT));
  assign axis_downsizer_bus.tvalid  = (state != GET_WORD_IN);

  assign axis_downsizer_bus.tdata  = mux_out_tdata;
  assign axis_downsizer_bus.tid    = tid_r;
  assign axis_downsizer_bus.tdest  = tdest_r;
  assign axis_downsizer_bus.tlast  = (select == S - 1) ? tlast_r : 1'b0;


  // --------------------------------------------------------------------
  //
  axis_register_slice #(.N(N), .U(U))
    axis_register_slice_i(.axis_in(axis_downsizer_bus), .*);


// --------------------------------------------------------------------
//
endmodule


Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.