calyx icon indicating copy to clipboard operation
calyx copied to clipboard

Papercut pass fails on components with multiple go/done pairs

Open andrewb1999 opened this issue 3 years ago • 0 comments

When I try to compile the following program (generated by circt and amc):

import "primitives/core.futil";
import "primitives/binary_operators.futil";
extern "amc.v" {
  primitive mem_0_prim[WIDTH, PORT0_SIZE, PORT0_IDX_SIZE, PORT1_SIZE, PORT1_IDX_SIZE](@clk clk: 1, port0_addr0: PORT0_IDX_SIZE, @go @static(1) port0_read_en: 1, port1_addr0: PORT1_IDX_SIZE, port1_write_data: WIDTH, @go(2) @static(1) port1_write_en: 1) -> (port0_read_data: WIDTH, @done port0_read_done: 1, @done(2) port1_write_done: 1);
}
component mem_0_comp(port0_addr0: 8, @go port0_read_en: 1, port1_addr0: 8, port1_write_data: 32, @go(2) port1_write_en: 1, @clk clk: 1, @reset reset: 1) -> (port0_read_data: 32, @done port0_read_done: 1, @done(2) port1_write_done: 1) {
  cells {
    mem_0 = mem_0_prim(32, 200, 8, 200, 8);
  }
  wires {
    mem_0.clk = clk;
    port0_read_data = mem_0.port0_read_data;
    mem_0.port0_read_en = port0_read_en;
    port0_read_done = mem_0.port0_read_done;
    mem_0.port0_addr0 = port0_addr0;
    mem_0.port1_write_data = port1_write_data;
    mem_0.port1_write_en = port1_write_en;
    port1_write_done = mem_0.port1_write_done;
    mem_0.port1_addr0 = port1_addr0;
  }
  control {
  }
}
component vadd<"toplevel"=1>(ext_mem0_read_data: 32, ext_mem0_done: 1, ext_mem1_read_data: 32, ext_mem1_done: 1, @clk clk: 1, @reset reset: 1, @go go: 1) -> (ext_mem0_write_data: 32, ext_mem0_addr0: 8, ext_mem0_write_en: 1, ext_mem1_write_data: 32, ext_mem1_addr0: 8, ext_mem1_write_en: 1, @done done: 1) {
  cells {
    std_slice_5 = std_slice(32, 8);
    std_slice_4 = std_slice(32, 8);
    std_slice_3 = std_slice(32, 8);
    std_slice_2 = std_slice(32, 8);
    std_slice_1 = std_slice(32, 8);
    std_slice_0 = std_slice(32, 8);
    std_add_3 = std_add(32);
    std_slt_2 = std_slt(32);
    std_add_2 = std_add(32);
    std_add_1 = std_add(32);
    std_slt_1 = std_slt(32);
    std_add_0 = std_add(32);
    std_slt_0 = std_slt(32);
    inst_1 = mem_0_comp();
    inst_0 = mem_0_comp();
    while_2_arg0_reg = std_reg(32);
    while_1_arg0_reg = std_reg(32);
    while_0_arg0_reg = std_reg(32);
  }
  wires {
    group assign_while_0_init_0 {
      while_0_arg0_reg.in = 32'd0;
      while_0_arg0_reg.write_en = 1'd1;
      assign_while_0_init_0[done] = while_0_arg0_reg.done;
    }
    group assign_while_1_init_0 {
      while_1_arg0_reg.in = 32'd0;
      while_1_arg0_reg.write_en = 1'd1;
      assign_while_1_init_0[done] = while_1_arg0_reg.done;
    }
    group assign_while_2_init_0 {
      while_2_arg0_reg.in = 32'd0;
      while_2_arg0_reg.write_en = 1'd1;
      assign_while_2_init_0[done] = while_2_arg0_reg.done;
    }
    comb group bb0_0 {
      std_slt_0.left = while_0_arg0_reg.out;
      std_slt_0.right = 32'd200;
    }
    group bb0_3 {
      std_slice_5.in = while_0_arg0_reg.out;
      std_slice_4.in = while_0_arg0_reg.out;
      inst_1.port1_addr0 = std_slice_5.out;
      inst_1.port1_write_data = ext_mem0_read_data;
      inst_1.port1_write_en = 1'd1;
      ext_mem0_addr0 = std_slice_4.out;
      bb0_3[done] = inst_1.port1_write_done;
    }
    group assign_while_0_latch {
      while_0_arg0_reg.in = std_add_0.out;
      while_0_arg0_reg.write_en = 1'd1;
      std_add_0.left = while_0_arg0_reg.out;
      std_add_0.right = 32'd1;
      assign_while_0_latch[done] = while_0_arg0_reg.done;
    }
    comb group bb0_4 {
      std_slt_1.left = while_1_arg0_reg.out;
      std_slt_1.right = 32'd200;
    }
    group bb0_8 {
      std_slice_3.in = while_1_arg0_reg.out;
      std_slice_2.in = while_1_arg0_reg.out;
      inst_0.port1_addr0 = std_slice_3.out;
      inst_0.port1_write_data = std_add_2.out;
      inst_0.port1_write_en = 1'd1;
      std_add_2.left = inst_1.port0_read_data;
      inst_1.port0_addr0 = std_slice_2.out;
      std_add_2.right = 32'd1;
      bb0_8[done] = inst_0.port1_write_done;
    }
    group assign_while_1_latch {
      while_1_arg0_reg.in = std_add_1.out;
      while_1_arg0_reg.write_en = 1'd1;
      std_add_1.left = while_1_arg0_reg.out;
      std_add_1.right = 32'd1;
      assign_while_1_latch[done] = while_1_arg0_reg.done;
    }
    comb group bb0_9 {
      std_slt_2.left = while_2_arg0_reg.out;
      std_slt_2.right = 32'd200;
    }
    group bb0_12 {
      std_slice_1.in = while_2_arg0_reg.out;
      std_slice_0.in = while_2_arg0_reg.out;
      ext_mem1_addr0 = std_slice_1.out;
      ext_mem1_write_data = inst_0.port0_read_data;
      ext_mem1_write_en = 1'd1;
      inst_0.port0_addr0 = std_slice_0.out;
      bb0_12[done] = ext_mem1_done;
    }
    group assign_while_2_latch {
      while_2_arg0_reg.in = std_add_3.out;
      while_2_arg0_reg.write_en = 1'd1;
      std_add_3.left = while_2_arg0_reg.out;
      std_add_3.right = 32'd1;
      assign_while_2_latch[done] = while_2_arg0_reg.done;
    }
  }
  control {
    seq {
      assign_while_0_init_0;
      while std_slt_0.out with bb0_0 {
        seq {
          bb0_3;
          assign_while_0_latch;
        }
      }
      assign_while_1_init_0;
      while std_slt_1.out with bb0_4 {
        seq {
          bb0_8;
          assign_while_1_latch;
        }
      }
      assign_while_2_init_0;
      while std_slt_2.out with bb0_9 {
        seq {
          bb0_12;
          assign_while_2_latch;
        }
      }
    }
  }
}

I get the following error:

Error: [Papercut] Component `mem_0_comp` has an empty control program and does not assign to the `done` port. Without an assignment to the `done`, the component cannot return control flow.

But I do assign to both done ports in wires. Calling futil with -d papercut works fine.

andrewb1999 avatar Oct 08 '22 15:10 andrewb1999