Skip to content

Commit

Permalink
Lift main-loop generator
Browse files Browse the repository at this point in the history
  • Loading branch information
anshumanmohan committed Jul 27, 2023
1 parent 6e69e5f commit 58d5c89
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 127 deletions.
139 changes: 139 additions & 0 deletions calyx-py/calyx/queue_call.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# pylint: disable=import-error
import calyx.builder as cb
import calyx.builder_util as util


def insert_raise_err_if_i_eq_15(prog):
"""Inserts a the component `raise_err_if_i_eq_15` into the program.
It has:
- one input, `i`.
- one ref register, `err`.
If `i` equals 15, it raises the `err` flag.
"""
raise_err_if_i_eq_15: cb.ComponentBuilder = prog.component("raise_err_if_i_eq_15")
i = raise_err_if_i_eq_15.input("i", 32)
err = raise_err_if_i_eq_15.reg("err", 1, is_ref=True)

i_eq_15 = util.insert_eq(raise_err_if_i_eq_15, i, 15, "i_eq_15", 32)
raise_err = util.insert_reg_store(raise_err_if_i_eq_15, err, 1, "raise_err")

raise_err_if_i_eq_15.control += [
cb.if_(
i_eq_15[0].out,
i_eq_15[1],
raise_err,
)
]

return raise_err_if_i_eq_15


def insert_main(prog, queue):
"""Inserts the component `main` into the program.
This will be used to `invoke` the component `queue` and feed it a list of commands.
"""
main: cb.ComponentBuilder = prog.component("main")

# The user-facing interface of the `main` component is:
# - a list of commands (the input)
# where each command is a 32-bit unsigned integer, with the following format:
# `0`: pop
# any other value: push that value
# - a list of answers (the output).
#
# The user-facing interface of the `queue` component is:
# - one input, `cmd`.
# where each command is a 32-bit unsigned integer, with the following format:
# `0`: pop
# any other value: push that value
# - one ref register, `ans`, into which the result of a pop is written.
# - one ref register, `err`, which is raised if an error occurs.

commands = main.seq_mem_d1("commands", 32, 15, 32, is_external=True)
ans_mem = main.seq_mem_d1("ans_mem", 32, 10, 32, is_external=True)

# The two components we'll use:
queue = main.cell("myqueue", queue)
raise_err_if_i_eq_15 = main.cell(
"raise_err_if_i_eq_15", insert_raise_err_if_i_eq_15(prog)
)

# We will use the `invoke` method to call the `queue` component.
# The queue component takes two inputs by reference and one input directly.
# The two `ref` inputs:
err = main.reg("err", 1) # A flag to indicate an error
ans = main.reg("ans", 32) # A memory to hold the answer of a pop

# We will set up a while loop that runs over the command list, relaying
# the commands to the `queue` component.
# It will run until the `err` flag is raised by the `queue` component.

i = main.reg("i", 32) # The index of the command we're currently processing
j = main.reg("j", 32) # The index on the answer-list we'll write to
cmd = main.reg("command", 32) # The command we're currently processing

zero_i = util.insert_reg_store(main, i, 0, "zero_i") # zero out `i`
zero_j = util.insert_reg_store(main, j, 0, "zero_j") # zero out `j`
incr_i = util.insert_incr(main, i, "incr_i") # i++
incr_j = util.insert_incr(main, j, "incr_j") # j++
err_eq_0 = util.insert_eq(main, err.out, 0, "err_eq_0", 1) # is `err` flag down?
cmd_eq_0 = util.insert_eq(main, cmd.out, 0, "cmd_eq_0", 32) # cmd == 0
cmd_neq_0 = util.insert_neq(
main, cmd.out, cb.const(32, 0), "cmd_neq_0", 32
) # cmd != 0

read_cmd = util.mem_read_seqd1(main, commands, i.out, "read_cmd_phase1")
write_cmd_to_reg = util.mem_write_seqd1_to_reg(
main, commands, cmd, "write_cmd_phase2"
)

write_ans = util.mem_store_seq_d1(main, ans_mem, j.out, ans.out, "write_ans")

main.control += [
zero_i,
zero_j,
cb.while_(
err_eq_0[0].out,
err_eq_0[1], # Run while the `err` flag is down
[
read_cmd, # Read `commands[i]`
write_cmd_to_reg, # Write it to `cmd`
cb.par( # Now, in parallel, act based on the value of `cmd`
cb.if_(
# Is this a pop?
cmd_eq_0[0].out,
cmd_eq_0[1],
[ # A pop
cb.invoke( # First we call pop
queue,
in_cmd=cmd.out,
ref_ans=ans,
ref_err=err,
),
# AM: my goal is that,
# if err flag comes back raised,
# we do not perform this write or this incr_j
write_ans,
incr_j,
],
),
cb.if_( # Is this a push?
cmd_neq_0[0].out,
cmd_neq_0[1],
cb.invoke( # A push
queue,
in_cmd=cmd.out,
ref_ans=ans,
ref_err=err,
),
),
),
incr_i, # Increment the command index
cb.invoke( # If i = 15, raise error flag
raise_err_if_i_eq_15, in_i=i.out, ref_err=err
), # AM: hella hacky
],
),
]
131 changes: 4 additions & 127 deletions calyx-py/test/correctness/fifo.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,7 @@
# pylint: disable=import-error
import calyx.builder as cb
import calyx.builder_util as util


def insert_raise_err_if_i_eq_15(prog):
"""Inserts a the component `raise_err_if_i_eq_15` into the program.
It has:
- one input, `i`.
- one ref register, `err`.
If `i` equals 15, it raises the `err` flag.
"""
raise_err_if_i_eq_15: cb.ComponentBuilder = prog.component("raise_err_if_i_eq_15")
i = raise_err_if_i_eq_15.input("i", 32)
err = raise_err_if_i_eq_15.reg("err", 1, is_ref=True)

i_eq_15 = util.insert_eq(raise_err_if_i_eq_15, i, 15, "i_eq_15", 32)
raise_err = util.insert_reg_store(raise_err_if_i_eq_15, err, 1, "raise_err")

raise_err_if_i_eq_15.control += [
cb.if_(
i_eq_15[0].out,
i_eq_15[1],
raise_err,
)
]

return raise_err_if_i_eq_15
import calyx.queue_call as qc


def insert_fifo(prog, name):
Expand All @@ -37,7 +11,7 @@ def insert_fifo(prog, name):
- one input, `cmd`.
- one memory, `mem`, of size 10.
- two registers, `next_write` and `next_read`.
- three ref registers, `ans`, `err`, and `len`.
- three ref registers, `ans` and `err`.
"""

fifo: cb.ComponentBuilder = prog.component(name)
Expand Down Expand Up @@ -155,108 +129,11 @@ def insert_fifo(prog, name):
return fifo


def insert_main(prog):
"""Inserts the component `main` into the program.
This will be used to `invoke` the component `fifo`.
"""
main: cb.ComponentBuilder = prog.component("main")

# The user-facing interface of the `main` component is:
# - a list of commands (the input)
# where each command is a 32-bit unsigned integer, with the following format:
# `0`: pop
# any other value: push that value
# - a list of answers (the output).
commands = main.seq_mem_d1("commands", 32, 15, 32, is_external=True)
ans_mem = main.seq_mem_d1("ans_mem", 32, 10, 32, is_external=True)

# The two components we'll use:
fifo = main.cell("myfifo", insert_fifo(prog, "fifo"))
raise_err_if_i_eq_15 = main.cell(
"raise_err_if_i_eq_15", insert_raise_err_if_i_eq_15(prog)
)

# We will use the `invoke` method to call the `fifo` component.
# The fifo component takes three `ref` inputs:
err = main.reg("err", 1) # A flag to indicate an error
ans = main.reg("ans", 32) # A memory to hold the answer of a pop

# We will set up a while loop that runs over the command list, relaying
# the commands to the `fifo` component.
# It will run until the `err` flag is raised by the `fifo` component.

i = main.reg("i", 32) # The index of the command we're currently processing
j = main.reg("j", 32) # The index on the answer-list we'll write to
cmd = main.reg("command", 32) # The command we're currently processing

zero_i = util.insert_reg_store(main, i, 0, "zero_i") # zero out `i`
zero_j = util.insert_reg_store(main, j, 0, "zero_j") # zero out `j`
incr_i = util.insert_incr(main, i, "incr_i") # i = i + 1
incr_j = util.insert_incr(main, j, "incr_j") # j = j + 1
err_eq_0 = util.insert_eq(main, err.out, 0, "err_eq_0", 1) # is `err` flag down?
cmd_eq_0 = util.insert_eq(main, cmd.out, 0, "cmd_eq_0", 32) # cmd == 0
cmd_neq_0 = util.insert_neq(
main, cmd.out, cb.const(32, 0), "cmd_neq_0", 32
) # cmd != 0

read_cmd = util.mem_read_seqd1(main, commands, i.out, "read_cmd_phase1")
write_cmd_to_reg = util.mem_write_seqd1_to_reg(
main, commands, cmd, "write_cmd_phase2"
)

write_ans = util.mem_store_seq_d1(main, ans_mem, j.out, ans.out, "write_ans")

main.control += [
zero_i,
zero_j,
cb.while_(
err_eq_0[0].out,
err_eq_0[1], # Run while the `err` flag is down
[
read_cmd, # Read `commands[i]`
write_cmd_to_reg, # Write it to `cmd`
cb.par(
cb.if_(
# Is this a pop?
cmd_eq_0[0].out,
cmd_eq_0[1],
[ # A pop
cb.invoke( # First we call pop
fifo,
in_cmd=cmd.out,
ref_ans=ans,
ref_err=err,
),
# AM: if err flag comes back raised,
# do not perform this write or this incr
write_ans,
incr_j,
],
),
cb.if_( # Is this a push?
cmd_neq_0[0].out,
cmd_neq_0[1],
cb.invoke( # A push
fifo,
in_cmd=cmd.out,
ref_ans=ans,
ref_err=err,
),
),
),
incr_i, # Increment the command index
cb.invoke( # If i = 15, raise error flag
raise_err_if_i_eq_15, in_i=i.out, ref_err=err
), # AM: hella hacky
],
),
]


def build():
"""Top-level function to build the program."""
prog = cb.Builder()
insert_main(prog)
fifo = insert_fifo(prog, "fifo")
qc.insert_main(prog, fifo)
return prog.program


Expand Down

0 comments on commit 58d5c89

Please sign in to comment.