// Demo 3b: A variation on demo_3a. That allocates array storage
// outside of a generate statement.

// A parameterized module that adds N to inputs 32-bit input
// Same as in demo 3a.
module AddN#(
  parameter N = 1
)(
  input  wire[31:0] x,
  output wire[31:0] y
);

  assign y = x + N;

endmodule

// A parameterized module that instantiates K adders in series
// Differences from demo 3a below
module Pipeline#(
  parameter K = 8
)(
  input  wire       clock,
  input  wire[31:0] x,
  output wire[31:0] y
);

  // Different from demo 3a: Storage declaration outside the generate loop
  reg[31:0] ris[K:0];

  genvar i;
  for (i = 1; i <= K; i = i + 1) begin : Adders
    wire[31:0] xi;
    always @(posedge clock)
      ris[i] <= xi;

    if (i == 1) 
      AddN#(i) adder(x, xi);
    else
      AddN#(i) adder(ris[i-1], xi);

  end

  // Different from demo 3: output attached to array
  assign y = ris[K];

endmodule

// A constant value declaration
localparam DEPTH = 10;

// Program input
// Same as in demo 2
reg[31:0] v0 = 0;

// Instantiate a pipeline with DEPTH adders
wire[31:0] vdepth;
Pipeline#(DEPTH) pipeline(clock.val, v0, vdepth);

// Print out what's going on in the pipeline
integer COUNT = 0;
always @(posedge clock.val) begin
  COUNT <= COUNT + 1;
  if (COUNT == DEPTH+1)
    $finish(1);
  else 
    $display("At the end of time %d: %d", COUNT, vdepth);
end        

// Things to try:
// 1. Run the program and verify that the outputs are the same as they were for demo_3a.

// Talking Points:
// 1. What's the difference between a scalar register of N bits, and an N-bit array of since bit scalars? 
// 2. What's the difference between an array of registers and registers declared inside of a generate loop?
