def test_intf_name_inference(): reg['gear/infer_signal_names'] = True @gear def fsub1(din1, din2) -> Tuple['din1', 'din2']: pass @gear def fsub2(din) -> b'din': pass @gear def fgear(din1, din2): var1 = fsub1(din1, din2) var2 = fsub2(var1) return var2 fgear(Intf(Uint[1]), Intf(Uint[2])) fsub1_inst = find('/fgear/fsub1') fsub2_inst = find('/fgear/fsub2') assert fsub1_inst.outputs[0].var_name == 'var1' assert fsub2_inst.outputs[0].var_name == 'var2'
def test_hier(): @gear def func1(arg1, arg2, arg3) -> Uint[4]: pass @gear def func2(arg1) -> Uint[2]: pass @gear def func_hier(arg1, arg2, arg3): return func1(arg1, arg2, arg3) | func2 iout = func_hier(Intf(Uint[1]), Intf(Uint[2]), Intf(Uint[3])) assert isinstance(iout, Intf) assert iout.dtype == Uint[2] root = reg['gear/root'] assert len(root.child) == 1 assert root['func_hier'].tout == Uint[2] for i in range(3): arg_intf = root['func_hier'].in_ports[i].consumer assert arg_intf.consumers[0] == root['func_hier/func1'].in_ports[i] assert root['func_hier/func1'].tout == Uint[4] iout1 = root['func_hier/func1'].outputs[0] assert iout1.producer == root['func_hier/func1'].out_ports[0] assert root['func_hier/func2'].tout == Uint[2] iout2 = root['func_hier/func2'].outputs[0] assert iout1.consumers == [root['func_hier/func2'].in_ports[0]] assert iout2.producer == root['func_hier/func2'].out_ports[0]
def test_le(): @gear def test(a: Fixp, b: Int): return a <= b test(Intf(Fixp[1, 16]), Intf(Int[16])) assert call(test, Fixp[1, 16](0), Int[16](0))[0] == 1 assert call(test, Fixp[1, 16](-0.01), Int[16](0))[0] == 1 assert call(test, Fixp[1, 16](0.01), Int[16](0))[0] == 0
def test_consumer_lower(): @gear def func(din, channeled) -> Tuple['din', 'channeled']: pass @gear def hier(din, *, f): return din | f hier(Intf(Uint[2]), f=func(channeled=Intf(Uint[1])))
def test_when(): @gear def ph_neg(data): return data + 1 @gear def ph_pos(data): return data + 1 return Intf(Uint[8]) | when(Intf(Uint[1]), f=ph_neg, fe=ph_pos)
def insert_module(port_name, module): port = find(port_name) post_intf = port.consumer post_intf.disconnect(port) if hasattr(post_intf, 'var_name'): post_intf.var_name += '_' + module.definition.__name__ pre_intf = Intf(post_intf.dtype) pre_intf.source(port) module(pre_intf, intfs=[post_intf])
def test_cordic_first_stage_vivado(): pw = 19 iw = 12 ow = 12 pw, ww, nstages, cordic_angles_l, gain = cordic_params(iw=iw, ow=ow, pw=pw) cordic_first_stage(Intf(Int[iw]), Intf(Int[iw]), Intf(Uint[pw]), iw=iw, ww=ww, pw=pw)
def test_consumer_lower_multilevel(): @gear def func(din, channeled) -> Tuple['din', 'channeled']: pass @gear def hier1(din, *, f): return din | f @gear def hier0(din, *, f): return din | f, din | f, hier1(din, f=f) hier0(Intf(Uint[2]), f=func(channeled=Intf(Uint[1])))
def test_hier_module_gen(): @gear def fgear(arg1, arg2) -> {'ret': Uint[2]}: pass @gear(outnames=['top_ret1', 'top_ret2']) def hier(top_din1, top_din2): ret1 = fgear(top_din1, top_din2) ret2 = fgear(ret1, top_din2) return ret1, ret2 hier(Intf(Uint[1]), Intf(Uint[2]))
def test_alternatives(): @gear(version=0) def fgear(arg1: Queue['T', 3], *, lvl=3) -> Tuple['T', Uint['lvl']]: pass @alternative(fgear) @gear(version=1) def fgear2(arg1: Queue['T', 2], *, lvl=2) -> Tuple['T', Uint['lvl']]: pass @alternative(fgear) @gear(version=2) def fgear1(arg1: Queue['T', 1], *, lvl=1) -> Tuple['T', Uint['lvl']]: pass @alternative(fgear) @gear(version=3) def fgear0(arg1: Uint['w'], *, lvl=0) -> Uint['w']: pass @alternative(fgear) @gear(version=4) def fgear01(arg1: Tuple['T1', 'T2'], *, lvl=0) -> b'T2': pass root = reg['gear/root'] iout = Intf(Uint[1]) | fgear assert iout.dtype == Uint[1] assert root['fgear'].params['lvl'] == 0 iout = Intf(Queue[Uint[1], 3]) | fgear assert iout.dtype == Tuple[Uint[1], Uint[3]] assert root['fgear1'].params['lvl'] == 3 iout = Intf(Queue[Uint[1], 1]) | fgear assert iout.dtype == Tuple[Uint[1], Uint[1]] assert root['fgear2'].params['lvl'] == 1 iout = Intf(Queue[Uint[1], 2]) | fgear assert iout.dtype == Tuple[Uint[1], Uint[2]] assert root['fgear3'].params['lvl'] == 2 iout = Intf(Tuple[Uint[1], Uint[2]]) | fgear assert iout.dtype == Uint[2] assert root['fgear4'].params['lvl'] == 0 assert root['fgear4'].meta_kwds['version'] == 4 assert len(root.child) == 5
def test_unionmap_simple_asymmetric(): @gear def test(din: Uint['size']) -> Uint['size+1']: pass iout = fmap(Intf(Union[Uint[8], Uint[8]]), f=(test, None)) assert iout.dtype == Union[Uint[9], Uint[8]]
def test_unionmap_simple(): @gear def test(din: Uint['size']) -> Uint['size+1']: pass iout = fmap(Intf(Union[Uint[1], Uint[2]]), f=(test, test)) assert iout.dtype == Union[Uint[2], Uint[3]]
def moving_average(cfg: TCfg, din: TDin, *, w_data=b'w_data'): second_operand = Intf(dtype=Int[w_data]) din_window = din \ | Int[w_data] \ | fifo(depth=8) initial_load = ccat(cfg['average_window'], const(val=0, tout=Int[w_data])) \ | replicate \ | Int[w_data] delayed_din = (initial_load, din_window) \ | priority_mux \ | union_collapse accum = din \ | fmap(f=accumulator(second_operand, delayed_din, w_data=w_data), lvl=din.dtype.lvl) accum_reg = accum | decoupler second_operand |= priority_mux(accum_reg | Int[w_data], const(val=0, tout=Int[w_data])) \ | union_collapse return accum
def test_queuemap_simple(): @gear def test(din: Uint[4]) -> Uint[2]: pass iout = fmap(Intf(Queue[Uint[4], 2]), f=test, lvl=2) assert iout.dtype == Queue[Uint[2], 2]
def test_queuemap_tuplemap(): @gear def test(din: Uint['size']) -> Uint['size+1']: pass iout = fmap(Intf(Queue[Tuple[Uint[1], Uint[2]], 2]), f=(test, test), lvl=3) assert iout.dtype == Queue[Tuple[Uint[2], Uint[3]], 2]
def dualcycle_wrap_thin(din) -> b'din[0][0]': middle = Intf(din.dtype[0]) return dualcycle(din, middle, intfs={'dout0': middle}, sim_cls=partial(SimVerilated, timeout=1))
def reduce2(din, cfg: TCfg, *, f, max_size): """Similar to the Python reduce function, applies a rolling computation to sequential pairs of values in a list. The ``din`` input is of type :class:`Queue` which holds the values to be used for computation while the ``cfg`` input is a :class:`Tuple` consisting of a ``reduce_size`` field and the ``init`` field holding the inital value. Args: f: Function to be performed max_size: Maximal length of the input `Queue` which is the depth of the FIFO used for storing intermediate values Returns: The result of the reduce operation """ acctype = cfg.dtype['init'] qtype = Queue[acctype, din.dtype.lvl - 1] temp_res = Intf(dtype=qtype) cfg_rep = cfg | replicate sec_opnd = (cfg_rep, temp_res) \ | priority_mux \ | fmap(f=union_collapse, fcat=czip, lvl=1) result = czip(din, sec_opnd) | decouple | fmap(f=f, fcat=czip, lvl=2) acc, fin_res = result | Union[qtype, qtype] | demux acc | fifo(intfs=[temp_res], depth=max_size) return fin_res
def test_mux_demux_redux_yosys(branches): TDin = Union[tuple(Uint[i] for i in range(1, branches + 1))] @gear def test(din): return demux_ctrl(din) | mux test(Intf(TDin))
def hdl_i(din, *, Ki): accum_s = Intf(Fixp[5, 28]) gain = din * Ki dout = gain + accum_s accum_s |= dout | dreg return dout
def dualcycle_wrap_comb_middle(din) -> b'din[0][0]': middle = Intf(din.dtype[0]) middle_back = (middle | fmap(f=(add(0), add(0)))) >> din.dtype[0] return dualcycle(din, middle_back, intfs={'dout0': middle}, sim_cls=partial(SimVerilated, timeout=1))
def iir_2tsos(din, *, a, b, gain): din = din * gain y = Intf(din.dtype * 5) a1 = ((din * b[2]) - (y * a[2])) z1 = a1 | dreg(init=0) z2 = ((din * b[1]) + z1 - (y * a[1])) | decouple(init=0) y |= (din * b[0]) + z2 return y
def dualcycle_wrap_decouple_middle(din) -> b'din[0][0]': middle = Intf(din.dtype[0]) middle_back = middle | decouple return dualcycle(din, middle_back, intfs={'dout0': middle}, sim_cls=partial(SimVerilated, timeout=1))
def sim_compile_resolver(func, *args, **kwds): ctx = reg['gear/exec_context'] if ctx == 'sim': reg['gear/exec_context'] = 'compile' local_in = [] for a in args: if isinstance(a, Intf): a.consumers.clear() local_in.append(a) else: from pygears.lib.const import get_literal_type local_in.append(Intf(get_literal_type(a))) local_in[-1].producer = HDLProducer() reg['gear/exec_context'] = 'sim' outputs = gear_base_resolver(func, *local_in, **kwds) # TODO: Support multiple outputs if isinstance(outputs, tuple): raise Exception("Not yet supported") outputs.connect(HDLConsumer()) gear_inst = outputs.producer.gear def is_async_gen(func): return bool(func.__code__.co_flags & inspect.CO_ASYNC_GENERATOR) if not is_async_gen(gear_inst.func): raise Exception("Not yet supported") import asyncio for intf, a in zip(local_in, args): if isinstance(a, Intf): continue intf._in_queue = asyncio.Queue(maxsize=1, loop=reg['sim/simulator']) intf.put_nb(a) simulator = reg['sim/simulator'] cur_sim = reg['gear/current_sim'] sim_map = reg['sim/map'] sim_gear = SimGear(gear_inst) sim_map[gear_inst] = sim_gear cur_sim.child.append(sim_gear) simulator.forward_ready.add(sim_gear) simulator.tasks[sim_gear] = sim_gear.run() simulator.task_data[sim_gear] = None return outputs else: return gear_base_resolver(func, *args, **kwds)
def test_cordic_stage_freduce_vivado(): pw = 19 iw = 12 ow = 12 cordic_stage(Intf(Tuple[Int[ow], Int[iw], Uint[pw]]), i=10, cordic_angle=Uint[pw](0x4fd9), ww=iw, pw=pw)
def test_cordic_pipeline_freduce_yosys(): pw = 19 iw = 12 ow = 12 cordic_stages(Intf(Tuple[Int[ow], Int[iw], Uint[pw]]), nstages=3, cordic_angles=[Uint[pw](0x4fd9)] * 3, ww=iw, pw=pw)
def test_cordic_sin_cos_s(): pw = 19 iw = 12 ow = 12 cordic_sin_cos(Intf(Uint[pw]), ow=ow, iw=iw, norm_gain_sin=False, norm_gain_cos=False)
def test_queuemap_balance(): @gear def bal(din: 'tdin') -> b'tdin': pass @gear def test(din: Uint['size']) -> Uint['size-1']: pass iout = fmap(Intf(Queue[Uint[4], 2]), f=test, lvl=2, balance=bal) assert iout.dtype == Queue[Uint[3], 2]
def test_incomplete_argument(): @gear def test(din) -> b'din': pass expected_err_text = """Input argument "din" has unresolved type "Integer"\n - when instantiating "test" """ with pytest.raises(GearArgsNotSpecified) as excinfo: test(Intf(Integer)) assert equal_on_nonspace(str(excinfo.value), expected_err_text)
def test_clk_channeling(): @gear def dut(din): return din \ | gear_clk2 Intf(Uint[16]) | dut mod_dut = find('/dut') assert InSig('clk2', 1) in mod_dut.meta_kwds['signals']
def test_unionmap_balance(): @gear def bal(din: 'tdin') -> b'tdin': pass @gear def test(din: Uint['size']) -> Uint['size+1']: pass iout = fmap(Intf(Union[Uint[1], Uint[2]]), f=(test, test), balance=bal) assert iout.dtype == Union[Uint[2], Uint[3]]