// Demo 6: Drive a program with a cascade fifo

// The code below is identical to demo 4, 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 4: Connect input to fifo  and output to memories
// See https://github.com/vmware/cascade/README.md for more on how fifos work
integer COUNT = 0;
wire empty;
wire[31:0] v0;
wire[31:0] v10;

(* __file="in.hex" *)
Fifo#(5, 8) in_fifo(
  .clock(clock.val),
  .rreq(!empty),
  .rdata(v0),
  .empty(empty)
);

localparam DEPTH = 10;
Pipeline#(DEPTH) pipeline(clock.val, v0, v10);

(* __file="out.hex" *)
Memory#(5, 8) out_mem(
  .clock(clock.val),
  .wen(COUNT >= 11),
  .waddr(COUNT-11),
  .wdata(v10)
);

always @(posedge clock.val) begin
  COUNT <= COUNT + 1;
  if (COUNT == 10+32) 
    $finish;
end

// Things to do:
// 1. Try changing the values in in.hex. Run the program and observe outputs in out.hex.
