calyx icon indicating copy to clipboard operation
calyx copied to clipboard

Bit splitting in Calyx.

Open cgyurgyik opened this issue 4 years ago • 7 comments
trafficstars

Sometimes we only want to access a certain subset of the bits in a multi-bit bus. std_slice provides limited functionality in this regard.

For example, in SV, we could access the ith bit of in with: in[i]. Following this, a Calyx interface for a single-bit split primitive might look like:

module std_split #(
  parameter WIDTH,
  parameter INDEX_SIZE
) (
  input wire logic [WIDTH-1:0]      in,
  input wire logic [INDEX_SIZE-1:0] index,
  output logic out;
);
  assign out = in[index];

  `ifdef VERILATOR
    always_comb begin
      if (index < 0 || index > (WIDTH - 1))
        $error(
          "std_split: Index is outside the bounds of the WIDTH.\n",
          "WIDTH: %0d", WIDTH,
          "index: %0d", index
        );
    end
  `endif
endmodule

This would require N individual std_splits to access each bit in a N-bit bus.

For example, we could also add an OUT_WIDTH if we want to split off a subset of bits with size > 1. We would then also need to provide a begin_index and end_index.

This also begs the question, perhaps we should differentiate between "compile-time"* splits and "runtime" splits? For example, if I know I will always want to access the first and second bit, then this would simply be a two wire split off the bus. I would imagine this is a bit more complicated when the index (or indices) are determined at runtime.

*There's probably better terminology that fits here

cgyurgyik avatar May 01 '21 14:05 cgyurgyik

Yes! It does seem like static vs. dynamic slices should probably be different primitives altogether. Static slices would get their indices as meta-level parameters, while dynamic slices would get their inputs as input wires. A good reason to separate them is that their costs are very different: static slices are effectively "free" in hardware, while dynamic slices are not.

sampsyo avatar May 02 '21 13:05 sampsyo

Would it suffice to make std_slice take a begin_index and end_index instead of just the out_index? For reference, std_slice does this:

  assign out = in[OUT_WIDTH-1:0];

rachitnigam avatar May 25 '21 14:05 rachitnigam

@cgyurgyik can add some context on where you were trying to use this?

rachitnigam avatar Aug 27 '21 12:08 rachitnigam

I don't recall (TCAM maybe?), but I imagine it would be useful to make certain wires of a bus available statically. I mean a concrete example would be ISA parser, but I don't think Calyx will target that.

For example,

[0][0][1][1] // Some 4-bit value
|    |     |

a = std_reg(2);
b = std_reg(2);

a = bit_slice(0, 2); // Statically known
b = bit_slice(2, 4);

Edit: A next step would be allowing arbitrary splicing, e.g. a=bit_slice(0, 3, 4) // Bits 0, 3, and 4.

cgyurgyik avatar Aug 27 '21 16:08 cgyurgyik

@rachitnigam I will like to tackle this issue. I suppose the plan is to go with your suggestion here?

anthonyabeo avatar Jan 20 '24 17:01 anthonyabeo

Hi, @anthonyabeo—I think that would be a good place to start! We would probably want to create a new, different primitive (to avoid conflicts with code that currently uses std_slice), and then consider migrating code over to it that could use the new primitive?

sampsyo avatar Jan 22 '24 01:01 sampsyo

@sampsyo sure, that sounds good. I'll put something together and revert.

anthonyabeo avatar Jan 23 '24 10:01 anthonyabeo