Skip to content

Commit

Permalink
std-bit-slice implementation (#1906)
Browse files Browse the repository at this point in the history
* add docs entry for std_bit_slice module

* add implementation of std_bit_slice module

* add test case for std_bit_slice module

* add test data for testing std_bit_slice module

* fix backward ordering of range extract parameters

* add 'std_bit_slice' implementation to interpreter

* change the Value.slice method to accept &self

* Update std-bit-slice test to use the new 'comb_mem_d1'

* Fix failing test

* Add 'std_bit_slice' definition to 'tests/import/a.expect'

* update std-bit-slice test
  • Loading branch information
anthonyabeo authored Feb 15, 2024
1 parent a2f2f3c commit cf547b4
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 3 deletions.
12 changes: 12 additions & 0 deletions docs/libraries/core.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,19 @@ Slice out the lower OUT_WIDTH bits of an IN_WIDTH-bit value. Computes
- `out: OUT_WIDTH` - The lower OUT_WIDTH bits of `in`

---
### `std_bit_slice<IN_WIDTH, START_IDX, END_IDX, OUT_WIDTH>`
Extract the bit-string starting at `START_IDX` and ending at `END_IDX - 1` from `in`.
This is computed as `in[END_IDX:START_IDX]`.`OUT_WIDTH` must be specified to
be `END_WIDTH - START_WITH` wide when instantiating the module.


**Inputs:**
- `in: IN_WIDTH` - An IN_WIDTH-bit value

**Outputs:**

- `out: OUT_WIDTH` - The value of the bit-string `in[START_IDX:END_IDX]`
---
### `std_pad<IN_WIDTH, OUT_WIDTH>`

Given an IN_WIDTH-bit input, zero pad from the left to an output of
Expand Down
4 changes: 4 additions & 0 deletions interp/src/primitives/combinational.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,10 @@ comb_primitive!(StdPad[IN_WIDTH, OUT_WIDTH](r#in: IN_WIDTH) -> (out: OUT_WIDTH)
Ok(r#in.ext(OUT_WIDTH as usize))
});

comb_primitive!(StdBitSlice[IN_WIDTH, START_IDX, END_IDX, OUT_WIDTH](r#in: IN_WIDTH) -> (out: OUT_WIDTH) {
Ok(r#in.slice(END_IDX as usize, START_IDX as usize))
});

// ===================== Unsynthesizeable Operations ======================
comb_primitive!(StdUnsynMult[WIDTH](left: WIDTH, right: WIDTH) -> (out: WIDTH) {
Ok(Value::from(left.as_unsigned() * right.as_unsigned(), WIDTH))
Expand Down
3 changes: 3 additions & 0 deletions interp/src/structures/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ impl InterpreterState {
Box::new(combinational::StdFpSlt::new(params, cell_qin))
}
// Resizing ops
"std_bit_slice" => {
Box::new(combinational::StdBitSlice::new(params, cell_qin))
}
"std_slice" => {
Box::new(combinational::StdSlice::new(params, cell_qin))
}
Expand Down
2 changes: 1 addition & 1 deletion interp/src/structures/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ impl Value {
}

/// Returns a value containing the sliced region \[lower,upper\]
pub fn slice(self, upper_idx: usize, lower_idx: usize) -> Self {
pub fn slice(&self, upper_idx: usize, lower_idx: usize) -> Self {
assert!(upper_idx >= lower_idx);
assert!(upper_idx < self.vec.len());

Expand Down
2 changes: 2 additions & 0 deletions primitives/core.futil
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ extern "core.sv" {
comb primitive std_slice<"share"=1>[IN_WIDTH, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH);
comb primitive std_pad<"share"=1>[IN_WIDTH, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH);
comb primitive std_cat<"share"=1>[LEFT_WIDTH, RIGHT_WIDTH, OUT_WIDTH](@data left: LEFT_WIDTH, @data right: RIGHT_WIDTH) -> (out: OUT_WIDTH);
comb primitive std_bit_slice<"share"=1>[IN_WIDTH, START_IDX, END_IDX, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH);


/// Logical operators
comb primitive std_not<"share"=1>[WIDTH](@data in: WIDTH) -> (out: WIDTH);
Expand Down
25 changes: 24 additions & 1 deletion primitives/core.sv
Original file line number Diff line number Diff line change
Expand Up @@ -217,4 +217,27 @@ module std_mux #(
assign out = cond ? tru : fal;
endmodule

`default_nettype wire
module std_bit_slice #(
parameter IN_WIDTH = 32,
parameter START_IDX = 0,
parameter END_IDX = 31,
parameter OUT_WIDTH = 32
)(
input wire logic [IN_WIDTH-1:0] in,
output logic [OUT_WIDTH-1:0] out
);
assign out = in[END_IDX:START_IDX];

`ifdef VERILATOR
always_comb begin
if (START_IDX < 0 || END_IDX > IN_WIDTH-1)
$error(
"std_bit_slice: Slice range out of bounds\n",
"IN_WIDTH: %0d", IN_WIDTH,
"START_IDX: %0d", START_IDX,
"END_IDX: %0d", END_IDX,
);
end
`endif

endmodule
25 changes: 24 additions & 1 deletion tests/backend/verilog/memory-with-external-attribute.expect
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,30 @@ module std_mux #(
assign out = cond ? tru : fal;
endmodule

`default_nettype wire
module std_bit_slice #(
parameter IN_WIDTH = 32,
parameter START_IDX = 0,
parameter END_IDX = 31,
parameter OUT_WIDTH = 32
)(
input wire logic [IN_WIDTH-1:0] in,
output logic [OUT_WIDTH-1:0] out
);
assign out = in[END_IDX:START_IDX];

`ifdef VERILATOR
always_comb begin
if (START_IDX < 0 || END_IDX > IN_WIDTH-1)
$error(
"std_bit_slice: Slice range out of bounds\n",
"IN_WIDTH: %0d", IN_WIDTH,
"START_IDX: %0d", START_IDX,
"END_IDX: %0d", END_IDX,
);
end
`endif

endmodule

module undef #(
parameter WIDTH = 32
Expand Down
5 changes: 5 additions & 0 deletions tests/correctness/std-bit-slice.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"mem": [
9
]
}
28 changes: 28 additions & 0 deletions tests/correctness/std-bit-slice.futil
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import "primitives/core.futil";
import "primitives/memories/comb.futil";

component main(@go go: 1) -> (@done done: 1) {
cells {
@external mem = comb_mem_d1(32, 1, 1);
slice = std_bit_slice(32, 10, 14, 4);
pad = std_pad(4, 32);
}

wires {
group bit_slice {
slice.in = 32'b00000000000000110010010110110000;

pad.in = slice.out;

mem.addr0 = 1'b0;
mem.write_data = pad.out;
mem.write_en = 1'b1;

bit_slice[done] = mem.done;
}
}

control {
bit_slice;
}
}
10 changes: 10 additions & 0 deletions tests/correctness/std-bit-slice.futil.data
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"mem": {
"data": [0],
"format": {
"numeric_type": "bitnum",
"is_signed": false,
"width": 32
}
}
}
1 change: 1 addition & 0 deletions tests/import/a.expect
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ extern "<ROOT>/calyx/primitives/core.sv" {
comb primitive std_slice<"share"=1>[IN_WIDTH, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH);
comb primitive std_pad<"share"=1>[IN_WIDTH, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH);
comb primitive std_cat<"share"=1>[LEFT_WIDTH, RIGHT_WIDTH, OUT_WIDTH](@data left: LEFT_WIDTH, @data right: RIGHT_WIDTH) -> (out: OUT_WIDTH);
comb primitive std_bit_slice<"share"=1>[IN_WIDTH, START_IDX, END_IDX, OUT_WIDTH](@data in: IN_WIDTH) -> (out: OUT_WIDTH);
comb primitive std_not<"share"=1>[WIDTH](@data in: WIDTH) -> (out: WIDTH);
comb primitive std_and<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) -> (out: WIDTH);
comb primitive std_or<"share"=1>[WIDTH](@data left: WIDTH, @data right: WIDTH) -> (out: WIDTH);
Expand Down

0 comments on commit cf547b4

Please sign in to comment.