// Demo 3a: Insert storage between the elements of the pipeline

// A parameterized module that adds N to inputs 32-bit input
// Same as in demo 1.
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 2 below
module Pipeline#(
  parameter K = 8
)(
  // Different from demo 2: A new input named clock
  input  wire       clock,
  input  wire[31:0] x,
  output wire[31:0] y
);

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

    // Different from demo 2: Declaration and update logic for storage here
    reg [31:0] ri = 0;
    always @(posedge clock) 
      ri <= xi;

    // Different from demo 2: the current state of the pipeline is
    // fed by the register from the previous stage
    if (i == 1) 
      AddN#(i) adder(x, xi);
    else
      AddN#(i) adder(Adders[i-1].ri, xi);

  end

  // Different from demo 2: output driven by register
  assign y = Adders[K].ri;

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. Observe the program output; we iterate 11 times, and then shutdown the program

// Talking Points:
// 1. What is clock.val? Where is it coming from?
// 2. The outputs might not have been what you expected --- why does the summation come out in reverse?
// 3. Cascade reports a clock frequency when it's done executing --- what clock is it referring to?
// 4. This example uses an integer variable --- is that meaningfully different than a register?
// 5. If we don't pass clock as an input to pipeline and refer to clock.val instead, the program still compiles --- why is that?
