Skip to content

Commit

Permalink
Merge branch 'main' into fud2-rhai-improved-errors
Browse files Browse the repository at this point in the history
  • Loading branch information
sgpthomas authored Jun 18, 2024
2 parents 9f68ff2 + 16e1835 commit 5a1a488
Show file tree
Hide file tree
Showing 27 changed files with 702 additions and 330 deletions.
74 changes: 69 additions & 5 deletions calyx-py/calyx/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,8 @@ def binary_use(self, left, right, cell, groupname=None):
with self.comb_group(groupname) as comb_group:
cell.left = left
cell.right = right
if not cell.is_comb():
cell.go = HI
return CellAndGroup(cell, comb_group)

def binary_use_names(self, cellname, leftname, rightname, groupname=None):
Expand Down Expand Up @@ -718,6 +720,16 @@ def not_use(self, input, cellname=None, width=None):
width = self.try_infer_width(width, input, input)
return self.unary_use(input, self.not_(width, cellname))

def mult_use(self, left, right, signed=False, cellname=None, width=None):
"""Inserts wiring into `self` to compute `left` * `right`."""
width = self.try_infer_width(width, left, right)
return self.binary_use(left, right, self.mult_pipe(width, cellname, signed))

def div_use(self, left, right, signed=False, cellname=None, width=None):
"""Inserts wiring into `self` to compute `left` * `right`."""
width = self.try_infer_width(width, left, right)
return self.binary_use(left, right, self.div_pipe(width, cellname, signed))

def bitwise_flip_reg(self, reg, cellname=None):
"""Inserts wiring into `self` to bitwise-flip the contents of `reg`
and put the result back into `reg`.
Expand All @@ -734,7 +746,7 @@ def bitwise_flip_reg(self, reg, cellname=None):

def incr(self, reg, val=1, signed=False, cellname=None, static=False):
"""Inserts wiring into `self` to perform `reg := reg + val`."""
cellname = cellname or f"{reg.name}_incr"
cellname = cellname or self.generate_name(f"{reg.name}_incr_{val}")
width = reg.infer_width_reg()
add_cell = self.add(width, cellname, signed)
group = (
Expand All @@ -753,7 +765,7 @@ def incr(self, reg, val=1, signed=False, cellname=None, static=False):

def decr(self, reg, val=1, signed=False, cellname=None):
"""Inserts wiring into `self` to perform `reg := reg - val`."""
cellname = cellname or f"{reg.name}_decr"
cellname = cellname or self.generate_name(f"{reg.name}_decr_{val}")
width = reg.infer_width_reg()
sub_cell = self.sub(width, cellname, signed)
with self.group(f"{cellname}_group") as decr_group:
Expand Down Expand Up @@ -885,18 +897,25 @@ def op_store_in_reg(
right,
cellname,
width,
ans_reg=None,
ans_reg=None
):
"""Inserts wiring into `self` to perform `reg := left op right`,
where `op_cell`, a Cell that performs some `op`, is provided.
"""

is_comb = op_cell.is_comb()
ans_reg = ans_reg or self.reg(width, f"reg_{cellname}")
with self.group(f"{cellname}_group") as op_group:
op_cell.left = left
op_cell.right = right
ans_reg.write_en = 1
ans_reg.in_ = op_cell.out

if not is_comb:
op_cell.go = HI

ans_reg.write_en = 1 if is_comb else op_cell.done @ 1
ans_reg.in_ = op_cell.out if is_comb else op_cell.done @ op_cell.out
op_group.done = ans_reg.done

return op_group, ans_reg

def add_store_in_reg(
Expand Down Expand Up @@ -955,6 +974,35 @@ def neq_store_in_reg(
cell = self.neq(width, cellname, signed)
return self.op_store_in_reg(cell, left, right, cell.name, 1, ans_reg)

def mult_store_in_reg(
self,
left,
right,
ans_reg=None,
cellname=None,
width=None,
signed=False
):
"""Inserts wiring into `self` to perform `reg := left * right`."""
width = width or self.try_infer_width(width, left, right)
cell = self.mult_pipe(width, cellname, signed)
return self.op_store_in_reg(cell, left, right, cell.name, width, ans_reg)

def div_store_in_reg(
self,
left,
right,
ans_reg=None,
cellname=None,
width=None,
signed=False
):
"""Inserts wiring into `self` to perform `reg := left / right`."""
width = width or self.try_infer_width(width, left, right)
cell = self.div_pipe(width, cellname, signed)
return self.op_store_in_reg(cell, left, right, cell.name, width, ans_reg)


def infer_width(self, expr) -> int:
"""Infer the width of an expression."""
if isinstance(expr, int): # We can't infer the width of an integer.
Expand Down Expand Up @@ -1342,6 +1390,22 @@ def is_primitive(self, prim_name) -> bool:
and self._cell.comp.id == prim_name
)

def is_comb(self) -> bool:
return self._cell.comp.id in (
"std_add",
"std_sub",
"std_lt",
"std_le",
"std_ge",
"std_gt",
"std_eq",
"std_neq",
"std_sgt",
"std_slt",
"std_fp_sgt",
"std_fp_slt",
)

def is_comb_mem_d1(self) -> bool:
"""Check if the cell is a StdMemD1 cell."""
return self.is_primitive("comb_mem_d1")
Expand Down
8 changes: 6 additions & 2 deletions calyx-py/calyx/fifo_oracle.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# For usage, see gen_queue_data_expect.sh

import sys
import calyx.queues as queues
from calyx import queue_util

if __name__ == "__main__":
max_cmds, len = int(sys.argv[1]), int(sys.argv[2])
commands, values = queue_util.parse_json()
fifo = queues.Fifo([], False)
ans = queues.operate_queue(commands, values, fifo)
fifo = queues.Fifo(len)
ans = queues.operate_queue(commands, values, fifo, max_cmds)
queue_util.dump_json(commands, values, ans)
17 changes: 17 additions & 0 deletions calyx-py/calyx/gen_queue_data_expect.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/bash

# For SDN, we use piezo mode when making the data file and
# use pifotree_oracle to generate the expected output
python3 queue_data_gen.py 20000 --no-err 16 > ../test/correctness/queues/sdn.data
cat ../test/correctness/queues/sdn.data | python3 pifo_tree_oracle.py 20000 16 > ../test/correctness/queues/sdn.expect

# For the others, we drop piezo mode for data gen, and we use the appropriate
# oracle, which is one of the following:
# - fifo_oracle.py
# - pifo_oracle.py
# - pifo_tree_oracle.py

for queue_kind in fifo pifo pifo_tree; do
python3 queue_data_gen.py 20000 --no-err 16 > ../test/correctness/queues/$queue_kind.data
cat ../test/correctness/queues/$queue_kind.data | python3 ${queue_kind}_oracle.py 20000 16 > ../test/correctness/queues/$queue_kind.expect
done
8 changes: 6 additions & 2 deletions calyx-py/calyx/pifo_oracle.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# For usage, see gen_queue_data_expect.sh

import sys
import calyx.queues as queues
from calyx import queue_util

if __name__ == "__main__":
max_cmds, len = int(sys.argv[1]), int(sys.argv[2])
commands, values = queue_util.parse_json()

# Our PIFO is simple: it just orchestrates two FIFOs. The boundary is 200.
pifo = queues.Pifo(queues.Fifo([]), queues.Fifo([]), 200, False)
pifo = queues.Pifo(queues.Fifo(len), queues.Fifo(len), 200, len)

ans = queues.operate_queue(commands, values, pifo)
ans = queues.operate_queue(commands, values, pifo, max_cmds)
queue_util.dump_json(commands, values, ans)
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
# Usage:
# To make a .data file:
# python calyx-py/calyx/queue_data_gen.py --piezo > calyx-py/test/correctness/sdn.data
# To then make a .expect file:
# cat calyx-py/test/correctness/sdn.data |
# python calyx-py/calyx/pifotree_oracle.py > calyx-py/test/correctness/sdn.expect
# For usage, see gen_queue_data_expect.sh

import sys
import calyx.queues as queues
from calyx import queue_util


if __name__ == "__main__":

max_cmds, len = int(sys.argv[1]), int(sys.argv[2])
commands, values = queue_util.parse_json()

# Our PIFO is a little complicated: it is a tree of queues.
Expand All @@ -23,8 +21,11 @@
# - The boundary for this is 200.

pifo = queues.Pifo(
queues.Pifo(queues.Fifo([]), queues.Fifo([]), 100), queues.Fifo([]), 200, False
queues.Pifo(queues.Fifo(len), queues.Fifo(len), 100, len),
queues.Fifo(len),
200,
len,
)

ans = queues.operate_queue(commands, values, pifo)
ans = queues.operate_queue(commands, values, pifo, max_cmds)
queue_util.dump_json(commands, values, ans)
20 changes: 10 additions & 10 deletions calyx-py/calyx/queue_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import calyx.builder as cb


def insert_runner(prog, queue, name, stats_component=None):
def insert_runner(prog, queue, name, num_cmds, stats_component=None):
"""Inserts the component `name` into the program.
This will be used to `invoke` the component `queue` and feed it one command.
This component is designed to be invoked by some other component, and does not
Expand Down Expand Up @@ -55,8 +55,8 @@ def insert_runner(prog, queue, name, stats_component=None):
# - ref register `err`, which is raised if an error occurs.

# Our memories and registers, all of which are passed to us by reference.
commands = runner.seq_mem_d1("commands", 2, queue_util.MAX_CMDS, 32, is_ref=True)
values = runner.seq_mem_d1("values", 32, queue_util.MAX_CMDS, 32, is_ref=True)
commands = runner.seq_mem_d1("commands", 2, num_cmds, 32, is_ref=True)
values = runner.seq_mem_d1("values", 32, num_cmds, 32, is_ref=True)
has_ans = runner.reg(1, "has_ans", is_ref=True)
ans = runner.reg(32, "component_ans", is_ref=True)
err = runner.reg(1, "component_err", is_ref=True)
Expand All @@ -77,8 +77,8 @@ def insert_runner(prog, queue, name, stats_component=None):
lower_has_ans = runner.reg_store(has_ans, 0, "lower_has_ans")
not_err = runner.not_use(err.out)

# Wiring that raises `err` iff `i = MAX_CMDS`.
check_if_out_of_cmds, _ = runner.eq_store_in_reg(i.out, queue_util.MAX_CMDS, err)
# Wiring that raises `err` iff `i = num_cmds`.
check_if_out_of_cmds, _ = runner.eq_store_in_reg(i.out, num_cmds, err)

runner.control += [
write_cmd_to_reg, # `cmd := commands[i]`
Expand Down Expand Up @@ -119,7 +119,7 @@ def insert_runner(prog, queue, name, stats_component=None):
return runner


def insert_main(prog, queue, controller=None, stats_component=None):
def insert_main(prog, queue, num_cmds, controller=None, stats_component=None):
"""Inserts the component `main` into the program.
It triggers the dataplane and controller components.
"""
Expand All @@ -128,16 +128,16 @@ def insert_main(prog, queue, controller=None, stats_component=None):

stats = main.cell("stats_main", stats_component) if stats_component else None
controller = main.cell("controller", controller) if controller else None
dataplane = insert_runner(prog, queue, "dataplane", stats_component)
dataplane = insert_runner(prog, queue, "dataplane", num_cmds, stats_component)
dataplane = main.cell("dataplane", dataplane)

has_ans = main.reg(1)
dataplane_ans = main.reg(32)
dataplane_err = main.reg(1)

commands = main.seq_mem_d1("commands", 2, queue_util.MAX_CMDS, 32, is_external=True)
values = main.seq_mem_d1("values", 32, queue_util.MAX_CMDS, 32, is_external=True)
ans_mem = main.seq_mem_d1("ans_mem", 32, queue_util.MAX_CMDS, 32, is_external=True)
commands = main.seq_mem_d1("commands", 2, num_cmds, 32, is_external=True)
values = main.seq_mem_d1("values", 32, num_cmds, 32, is_external=True)
ans_mem = main.seq_mem_d1("ans_mem", 32, num_cmds, 32, is_external=True)

ans_neq_0 = main.neq_use(dataplane_ans.out, 0) # ans != 0

Expand Down
Loading

0 comments on commit 5a1a488

Please sign in to comment.