Skip to content

Commit

Permalink
Queues all working!
Browse files Browse the repository at this point in the history
  • Loading branch information
polybeandip committed Jun 18, 2024
1 parent 00f7bbb commit faf8dd7
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 165 deletions.
173 changes: 110 additions & 63 deletions calyx-py/test/correctness/queues/binheap/binheap.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@
from calyx.tuple import insert_tuplify, insert_untuplify


def insert_swap(prog, name, width, len, idx_w):
def insert_swap(prog, name, width, size, idx_w):
"""Inserts the component `swap` into the program.
It takes two `idx_w`-bit inputs `a` and `b` and accepts a memory by reference.
The memory is a `len`-element memory of `width`-bit elements.
The memory is a `size`-element memory of `width`-bit elements.
It swaps the values in the memory at addresses `a` and `b`.
"""

comp = prog.component(name)

a = comp.input("a", idx_w)
b = comp.input("b", idx_w)
mem = comp.seq_mem_d1("mem", width, len, idx_w, is_ref=True)
mem = comp.seq_mem_d1("mem", width, size, idx_w, is_ref=True)

val_a = comp.reg(width)
val_b = comp.reg(width)
Expand All @@ -31,20 +31,21 @@ def insert_swap(prog, name, width, len, idx_w):
return comp


def insert_binheap(prog, name, queue_len_factor):
def insert_binheap(prog, name, queue_size_factor):
"""Inserts the component `binheap` into the program.
It is a minimum binary heap, represented as an array.
It has:
- three inputs, `cmd`, `value`, and `rank`.
- one memory, `mem`, of size `(2**queue_len_factor)`.
- one memory, `mem`, of size `2**queue_size_factor`.
- two ref registers, `ans` and `err`.
"""

comp = prog.component(name)

max_queue_len = 2**queue_len_factor
max_queue_size = 2**queue_size_factor
addr_size = queue_size_factor

cmd = comp.input("cmd", 2)
# If it is 0, we pop.
Expand All @@ -55,13 +56,11 @@ def insert_binheap(prog, name, queue_len_factor):
rank = comp.input("rank", 64)
value = comp.input("value", 32)

swap = comp.cell(
"swap", insert_swap(prog, "swap", 96, max_queue_len, queue_len_factor)
)
swap = comp.cell("swap", insert_swap(prog, "swap", 96, max_queue_size, addr_size))
tuplify = comp.cell("tuplify", insert_tuplify(prog, "tuplify", 64, 32))
untuplify = comp.cell("untuplify", insert_untuplify(prog, "untuplify", 64, 32))

mem = comp.seq_mem_d1("mem", 96, max_queue_len, queue_len_factor)
mem = comp.seq_mem_d1("mem", 96, max_queue_size, addr_size)
# The memory to store the heap, represented as an array.
# Each cell of the memory is 96 bits wide: a 64-bit rank and a 32-bit value.

Expand All @@ -71,7 +70,7 @@ def insert_binheap(prog, name, queue_len_factor):
err = comp.reg(1, "err", is_ref=True)
# We'll raise this as a general error flag for overflow and underflow.

size = comp.reg(queue_len_factor) # The active length of the heap.
size = comp.reg(addr_size) # The active size of the heap.

# Cells and groups to check which command we got.
cmd_eq_0 = comp.eq_use(cmd, 0)
Expand All @@ -80,18 +79,20 @@ def insert_binheap(prog, name, queue_len_factor):

# Cells and groups to check for overflow and underflow.
size_eq_0 = comp.eq_use(size.out, 0)
size_eq_max = comp.eq_use(size.out, max_queue_len - 1)
full = comp.reg(1)
set_full_on = comp.reg_store(full, 1, "set_full_on")
set_full_off = comp.reg_store(full, 0, "set_full_off")

current_idx = comp.reg(queue_len_factor)
current_idx = comp.reg(addr_size)
current_rank = comp.reg(64)

parent_idx = comp.reg(queue_len_factor)
parent_idx = comp.reg(addr_size)
parent_rank = comp.reg(64)

child_l_idx = comp.reg(queue_len_factor)
child_l_idx = comp.reg(addr_size)
child_l_rank = comp.reg(64)

child_r_idx = comp.reg(queue_len_factor)
child_r_idx = comp.reg(addr_size)
child_r_rank = comp.reg(64)

# current_idx := 0
Expand All @@ -115,29 +116,29 @@ def insert_binheap(prog, name, queue_len_factor):
# err := 0
lower_err = comp.reg_store(err, 0, "lower_err")

sub = comp.sub(queue_len_factor)
rsh = comp.rsh(queue_len_factor)
sub = comp.sub(addr_size)
rsh = comp.rsh(addr_size)
with comp.group("find_parent_idx") as find_parent_idx:
# Find the parent of the `current_idx`th element and store it in `parent_idx`.
# parent_idx := floor((current_idx − 1) / 2)
sub.left = current_idx.out
sub.right = 1
rsh.left = sub.out
rsh.right = cb.const(queue_len_factor, 1)
rsh.right = cb.const(addr_size, 1)
parent_idx.in_ = rsh.out
parent_idx.write_en = cb.HI
find_parent_idx.done = parent_idx.done

add_1 = comp.add(queue_len_factor)
add_2 = comp.add(queue_len_factor)
lsh = comp.lsh(queue_len_factor)
add_1 = comp.add(addr_size)
add_2 = comp.add(addr_size)
lsh = comp.lsh(addr_size)
with comp.group("find_child_idx") as find_child_idx:
# Find the children of `current_idx`th element and store
# them in child_l_idx and child_r_idx.
# child_l_idx := (2 * current_idx) + 1
# child_r_idx := (2 * current_idx) + 2
lsh.left = current_idx.out
lsh.right = cb.const(queue_len_factor, 1)
lsh.right = cb.const(addr_size, 1)
add_1.left = 1
add_1.right = lsh.out
child_l_idx.write_en = cb.HI
Expand Down Expand Up @@ -203,56 +204,90 @@ def extract_snd(name, idx, out):
child_r_rank,
)

# current_rank < parent_rank
current_lt_parent = comp.lt_use(current_rank.out, parent_rank.out)

le_1 = comp.le(queue_len_factor)
le_2 = comp.le(64)
lt_1 = comp.lt(64)
lt_2 = comp.lt(addr_size)
while_and = comp.and_(1)
with comp.comb_group("current_lt_parent") as current_lt_parent:
# Check if the `current_idx`th element should be swapped with its parent.
# current_rank < parent_rank AND parent_idx < current_idx
lt_1.left = current_rank.out
lt_1.right = parent_rank.out

lt_2.left = parent_idx.out
lt_2.right = current_idx.out

while_and.left = lt_1.out
while_and.right = lt_2.out

le_1 = comp.le(addr_size)
le_2 = comp.le(addr_size)
le_3 = comp.le(64)
inner_or = comp.or_(1)
if_or = comp.or_(1)
with comp.comb_group("child_l_swap") as child_l_swap:
# Check if the `current_idx`th element should be swapped with its left child.
# size <= child_r_idx OR child_l_rank <= child_r_rank
# size <= child_r_idx OR child_r_idx <= current_idx OR child_l_rank <= child_r_rank
le_1.left = size.out
le_1.right = child_r_idx.out

le_2.left = child_l_rank.out
le_2.right = child_r_rank.out
le_2.left = child_r_idx.out
le_2.right = current_idx.out

le_3.left = child_l_rank.out
le_3.right = child_r_rank.out

if_or.left = le_1.out
if_or.right = le_2.out
inner_or.left = le_1.out
inner_or.right = le_2.out

lt_1 = comp.lt(queue_len_factor)
lt_2 = comp.lt(64)
lt_3 = comp.lt(queue_len_factor)
lt_4 = comp.lt(64)
and_1 = comp.and_(1)
and_2 = comp.and_(1)
if_or.left = inner_or.out
if_or.right = le_3.out

lt_l_1 = comp.lt(addr_size)
lt_l_2 = comp.lt(addr_size)
lt_l_3 = comp.lt(64)
lt_r_1 = comp.lt(addr_size)
lt_r_2 = comp.lt(addr_size)
lt_r_3 = comp.lt(64)
and_l_1 = comp.and_(1)
and_l_2 = comp.and_(1)
and_r_1 = comp.and_(1)
and_r_2 = comp.and_(1)
while_or = comp.or_(1)
with comp.comb_group("current_gt_children") as current_gt_children:
# Check if the `current_idx`th element should be swapped with its left OR right.
# child_l_idx < size AND child_l_rank < current_rank
# Check if the `current_idx`th element should be swapped with its left OR right child.
# child_l_idx < size AND current_idx < child_l_idx AND child_l_rank < current_rank
# OR
# child_r_idx < size AND child_r_rank < current_rank
lt_1.left = child_l_idx.out
lt_1.right = size.out
# child_r_idx < size AND current_idx < child_r_idx AND child_r_rank < current_rank
lt_l_1.left = child_l_idx.out
lt_l_1.right = size.out

lt_l_2.left = current_idx.out
lt_l_2.right = child_l_idx.out

lt_2.left = child_l_rank.out
lt_2.right = current_rank.out
lt_l_3.left = child_l_rank.out
lt_l_3.right = current_rank.out

lt_3.left = child_r_idx.out
lt_3.right = size.out
lt_r_1.left = child_r_idx.out
lt_r_1.right = size.out

lt_4.left = child_r_rank.out
lt_4.right = current_rank.out
lt_r_2.left = current_idx.out
lt_r_2.right = child_r_idx.out

and_1.left = lt_1.out
and_1.right = lt_2.out
lt_r_3.left = child_r_rank.out
lt_r_3.right = current_rank.out

and_2.left = lt_3.out
and_2.right = lt_4.out
and_l_1.left = lt_l_1.out
and_l_1.right = lt_l_2.out
and_l_2.left = and_l_1.out
and_l_2.right = lt_l_3.out

while_or.left = and_1.out
while_or.right = and_2.out
and_r_1.left = lt_r_1.out
and_r_1.right = lt_r_2.out
and_r_2.left = and_r_1.out
and_r_2.right = lt_r_3.out

while_or.left = and_l_2.out
while_or.right = and_r_2.out

peek = extract_snd("peek", 0, ans)

Expand All @@ -261,6 +296,7 @@ def extract_snd(name, idx, out):
comp.decr(size),
set_idx_zero,
cb.invoke(swap, in_a=current_idx.out, in_b=size.out, ref_mem=mem),
comp.mem_store_d1(mem, size.out, cb.const(96, 0), "zero_leaf"),
extract_current_rank,
find_child_idx,
extract_child_l_rank,
Expand Down Expand Up @@ -306,7 +342,7 @@ def extract_snd(name, idx, out):
extract_current_rank,
# Bubble Up
cb.while_with(
current_lt_parent,
cb.CellAndGroup(while_and, current_lt_parent),
[
cb.invoke(swap, in_a=parent_idx.out, in_b=current_idx.out, ref_mem=mem),
set_idx_parent,
Expand All @@ -320,12 +356,23 @@ def extract_snd(name, idx, out):
lower_err,
cb.if_with(
cmd_eq_0,
cb.if_with(size_eq_0, raise_err, pop),
cb.if_(full.out,
[pop, set_full_off],
cb.if_with(size_eq_0, raise_err, pop)
),
cb.if_with(
cmd_eq_1,
cb.if_with(size_eq_0, raise_err, peek),
cb.if_(full.out,
peek,
cb.if_with(size_eq_0, raise_err, peek)
),
cb.if_with(
cmd_eq_2, cb.if_with(size_eq_max, raise_err, push), raise_err
cmd_eq_2,
[
cb.if_(full.out, raise_err, push),
cb.if_with(size_eq_0, set_full_on)
],
raise_err
),
),
),
Expand Down Expand Up @@ -362,12 +409,12 @@ def insert_main(prog):

comp = prog.component("main")

queue_len_factor = 4
queue_size_factor = 4

binheap = insert_binheap(prog, "binheap", queue_len_factor)
binheap = insert_binheap(prog, "binheap", queue_size_factor)
binheap = comp.cell("binheap", binheap)

out = comp.seq_mem_d1("out", 32, 15, queue_len_factor, is_external=True)
out = comp.seq_mem_d1("out", 32, 15, queue_size_factor, is_external=True)

ans = comp.reg(32)
err = comp.reg(1)
Expand Down
20 changes: 13 additions & 7 deletions calyx-py/test/correctness/queues/binheap/fifo.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@
from stable_binheap import insert_stable_binheap


def insert_binheap_fifo(prog, name, factor):
def insert_binheap_fifo(prog, name, queue_size_factor):
"""Inserts the component `fifo` into the program.
It is implemented via a binary heap
It is a first in, first out queue implemented via binary heap
It has:
- two inputs, `cmd` and `value`.
- one memory, `mem`, of size 10.
- two registers, `next_write` and `next_read`.
- one memory, `mem`, of size `2**queue_size_factor`.
- two ref registers, `ans` and `err`.
"""
comp = prog.component(name)

binheap = insert_stable_binheap(prog, "binheap", factor)
binheap = insert_stable_binheap(prog, "binheap", queue_size_factor)
binheap = comp.cell("binheap", binheap)

cmd = comp.input("cmd", 2)
Expand All @@ -28,7 +27,14 @@ def insert_binheap_fifo(prog, name, factor):
err = comp.reg(1, "err", is_ref=True)

comp.control += [
cb.invoke(binheap, in_value=value, in_rank=cb.const(32, 1), in_cmd=cmd, ref_ans=ans, ref_err=err),
cb.invoke(
binheap,
in_value=value,
in_rank=cb.const(32, 1),
in_cmd=cmd,
ref_ans=ans,
ref_err=err,
)
]

return comp
Expand All @@ -38,7 +44,7 @@ def build():
"""Top-level function to build the program."""
num_cmds = int(sys.argv[1])
prog = cb.Builder()
fifo = insert_binheap_fifo(prog, "fifo", 6)
fifo = insert_binheap_fifo(prog, "fifo", 4)
qc.insert_main(prog, fifo, num_cmds)
return prog.program

Expand Down
Loading

0 comments on commit faf8dd7

Please sign in to comment.