module pack_network #(
  parameter PORT_ADDRESS_WIDTH = 1,
  parameter MUX_ORDER = 1,
  parameter MIN_STAGE = 1,
  parameter NUM_STAGES = 1,
  parameter PACK = 0,
  parameter PORT_DATA_WIDTH = 16
) (
  input clk,
  input ce_ctrl,

  input [PORT_ADDRESS_WIDTH-1:0] rotate,
  input [2**PORT_ADDRESS_WIDTH*PORT_ADDRESS_WIDTH-1:0] prefix_count,

  input [PORT_DATA_WIDTH * 2**PORT_ADDRESS_WIDTH-1:0] data_in,
  output [PORT_DATA_WIDTH * 2**PORT_ADDRESS_WIDTH-1:0] data_out
);

  localparam CTRL_WIDTH = 2**PORT_ADDRESS_WIDTH * NUM_STAGES * MUX_ORDER;

  wire [CTRL_WIDTH-1:0] ctrl_s;
  reg [CTRL_WIDTH-1:0] ctrl = 'h00;
  wire [CTRL_WIDTH-1:0] ctrl_;

  pack_ctrl #(
    .PORT_ADDRESS_WIDTH (PORT_ADDRESS_WIDTH),
    .MUX_ORDER (MUX_ORDER),
    .MIN_STAGE (MIN_STAGE),
    .NUM_STAGES (NUM_STAGES),
    .PACK (PACK)
  ) i_ctrl (
    .rotate(rotate),
    .prefix_count(prefix_count),
    .ctrl(ctrl_s)
  );

  always @(posedge clk) begin
    if (ce_ctrl == 1'b1) begin
      ctrl <= ctrl_s;
    end
  end

  /*
   * Special optimization for 2-MUXes. In this case both control signals are
   * the same.
   */
  generate
    genvar i;
    if (MUX_ORDER == 1) begin
      for (i = 1; i < CTRL_WIDTH; i = i + 2) begin: gen_ctrl
        assign ctrl_[i] = ctrl[i];
        assign ctrl_[i-1] = ~ctrl[i];
      end
    end else begin
      assign ctrl_ = ctrl;
    end
  endgenerate

  pack_interconnect #(
    .PORT_DATA_WIDTH (PORT_DATA_WIDTH),
    .PORT_ADDRESS_WIDTH (PORT_ADDRESS_WIDTH),
    .MUX_ORDER (MUX_ORDER),
    .NUM_STAGES (NUM_STAGES),
    .PACK (PACK)
  ) i_interconnect (
    .ctrl(ctrl_),

    .data_in(data_in),
    .data_out(data_out)
  );

endmodule