control_flow

Iterator #(int MAX)

module Iterator #(int MAX) {
    output state bool may_next'0
    action start'0 : int #(FROM: 0, TO: MAX + 2) up_to'0
    action next'0 : -> int #(FROM: 0, TO: MAX + 1) value'0, bool last'0
}

FixedSizeIterator #(int TO)

module FixedSizeIterator #(int TO) {
    output state bool may_next'0
    action start'0
    action next'0 : -> int #(FROM: 0, TO) value'0, bool last'0
}

SlowState #(T, T RESET_TO, int OLD_DELAY, int NEW_DELAY)

Allows us to update a blob of state with a pipelined update function update() may only be called if may_update, upon which may_update goes low for UPDATE_PIPELINE_DEPTH cycles

module SlowState #(T, T RESET_TO, int OLD_DELAY, int NEW_DELAY) {
    clock clk
    action rst
    output state T old'-OLD_DELAY
    output bool may_update'0
    action update'0 : T new'NEW_DELAY
}

SlowPipelineEnd #(T, int PIPELINE_DEPTH)

This module lets you wait until all values within a pipeline have stabilized, and use the results as if the pipeline completed instantaneously.

As opposed to SlowPipelineBegin, this module is meant to go at the end of your pipeline

Usage:

Example

state float cur_sum'0
 SlowPipelineEnd manage_adder
  
 float next_sum'11 = fp32_add(cur_sum, 1.0) // Takes 11 cycles
 manage_adder.din = next_sum
 when manage_adder.pipeline_stable : float new_sum {
     cur_sum = new_sum
     manage_adder.input_changed()
 }
module SlowPipelineEnd #(T, int PIPELINE_DEPTH) {
    input T din'PIPELINE_DEPTH
    action input_changed'0
    trigger pipeline_stable'0 : T dout'0
    action rst
}

SlowPipelineBegin #(T, int PIPELINE_DEPTH)

This module lets you wait until all values within a pipeline have stabilized, and use the results as if the pipeline completed instantaneously.

As opposed to SlowPipelineEnd, this module is meant to go at the beginning of your pipeline

Usage:

Example

state float cur_sum'0
 SlowPipeline manage_adder
 manage_adder.din = cur_sum
  
 float next_sum'11 = fp32_add(manage_adder.dout, 1.0) // Takes 11 cycles
 when manage_adder.pipeline_stable {
     cur_sum = next_sum
     manage_adder.input_changed()
 }
module SlowPipelineBegin #(T, int PIPELINE_DEPTH) {
    input T din'0
    action input_changed'0
    output T dout'-PIPELINE_DEPTH
    trigger pipeline_stable'0
    action rst
}

ParallelWhile #(int COMPUTATION_LATENCY, int REQUEST_DATA_LATENCY)

This module lets you create pipelined feedback loops of variable latency.

Use as follows:

The order in which results arrive is not the same as the order of inputs, due to some taking more cycles to execute.

Example

FIFO input_fifo
 trigger outflow: int assoc_data
  
 ParallelWhile pw
 ParallelState cur_iter
 ParallelStore associated_data
 when pw.may_start {
     // gather up data
     when input_fifo.may_pop {
         int num_iters = input_fifo.pop()
         cur_iter.init(num_iters)
         associated_data.init(num_iters)
         pw.start()
     }
 }
  
 when pw.iter : int iteration {
     cur_iter.link(iteration)
     associated_data.link(iteration)
     int num_iters_left = cur_iter.old
     when num_iters_left > 0 {
         reg reg reg cur_iter.new = UnsafeIntCast#(FROM: 0, TO)(num_iters_left - 1)
         pw.continue()
     } else {
         outflow(associated_data.old)
     }
 }
module ParallelWhile #(int COMPUTATION_LATENCY, int REQUEST_DATA_LATENCY) {
    clock clk
    trigger iter'0 : int #(FROM: 0, TO: TOTAL_CYCLES) cur_iter'0
    action continue'COMPUTATION_LATENCY
    trigger may_start'-REQUEST_DATA_LATENCY
    action start'0
    action rst
}

ParallelState #(T, int NUM_PARALLEL_STATES, int LATENCY)

See ParallelWhile

Similar to ParallelStore

Must be initialized simultaneously with ParallelWhile::start (with ParallelState::init). Old data can be read from ParallelState::old Data must be updated through ParallelState::new every cycle

module ParallelState #(T, int NUM_PARALLEL_STATES, int LATENCY) {
    action link'0 : int#(FROM: 0, TO: NUM_PARALLEL_STATES) cur_iter_id'0
    output T old'2
    action init'0 : T initial_data'0
    input T new'LATENCY
}

ParallelStore #(T, int NUM_PARALLEL_STATES)

See ParallelWhile

Similar to ParallelState, but only initialized once, simultaneously with ParallelWhile::start. Data is returned every cycle on ParallelStore::old. Old data can be read from ParallelState::old

module ParallelStore #(T, int NUM_PARALLEL_STATES) {
    action link'0 : int#(FROM: 0, TO: NUM_PARALLEL_STATES) cur_iter_id'0
    output T old'3
    action init'0 : T initial_data'0
}