// Demo 4a: Drive a program with external values

// The code below is identical to demo 3a, just condensed
module AddN#(
  parameter N = 1
)(
  input  wire[31:0] x,
  output wire[31:0] y
);
  assign y = x + N;
endmodule

module Pipeline#(
  parameter K = 8
)(
  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;
    reg [31:0] ri = 0;
    always @(posedge clock) 
      ri <= xi;
    
    if (i == 1) 
      AddN#(i) adder(x, xi);
    else
      AddN#(i) adder(Adders[i-1].ri, xi);
  end

  assign y = Adders[K].ri;
endmodule

// Different from demo 3a: Connect inputs and outputs to I/O peripherals
localparam DEPTH = 10;
Pipeline#(DEPTH) pipeline(clock.val, pad.val, led.val);

// Things to do:
// 1. Try toggling changing pad values and watch the led values change in response

// Talking points:
// 1. What's going on behind the scenes? How are values moving to/from a different process?
// 2. What happens if we run cascade on a different platform? Say, on the de10?
