def get_int_type(val): if val == 0: return Uint[1] elif val > 0: return Uint[bitw(val)] else: return Int[bitw(val)]
def funclut(x: Fixpnumber, *, f, precision=b'x.width', dtype=None): '''Implement arbitrary 1 input parameter function as Lookup-table for integers. f is arbitrary function e.g. math.sqrt, precision is a number of bits the function result will be represented with, sqrt_lut: x | funclut(f=math.sqrt, precision=4) ''' din_t = x.dtype step = 2**(-din_t.fract) w_din = len(din_t) def gen_vals_signed(): for i in range(2**w_din): if i < (1 << (w_din - 1)): yield f(step * i) else: yield f(step * (i - (1 << w_din))) def gen_vals_unsigned(): for i in range(2**w_din): yield f(step * i) def gen_vals(): if din_t.signed: yield from gen_vals_signed() else: yield from gen_vals_unsigned() if dtype is None: float_res_list = list(gen_vals()) vmin = min(map(round, float_res_list)) vmax = max(map(round, float_res_list)) if vmin < 0: dtype = Fixp[bitw( max(2 * abs(vmin), 2 * (vmax) + (1 if vmax > 0 else 0))), precision] else: dtype = Ufixp[bitw(max(vmax, vmin)), precision] lut_list = [dtype(v) for v in float_res_list] else: lut_list = [dtype(v) for v in gen_vals()] dout = x >> Uint[w_din] | rom(data=lut_list, dtype=dtype) return dout
def test_buck_converter(): spice_library = SpiceLibrary(os.path.abspath(os.path.dirname(__file__))) spice_library['1N4148'] Vin = 20 @ u_V Vout = 15 @ u_V Vpulse = 5 @ u_V ratio = Vout / Vin clk_freq = 1 @ u_MHz clk_period = clk_freq.period sw_freq = 50 @ u_kHz sw_period = sw_freq.period sw_period_cnt = int(sw_period / clk_period) sw_width_cnt = int(sw_period_cnt * (1 - ratio)) w_period = bitw(sw_period_cnt) def buck_converter(c, ins, outs): c.include(spice_library['1N4148']) ins.append(('gate', c.gnd)) outs.append(('output', c.gnd)) Rload = 3 @ u_Ohm L = 750 @ u_uH Cout = 0.47 @ u_uF c.V('input', 'vin', c.gnd, Vin) c.VCS(name='sw1', input_plus='gate', input_minus=c.gnd, output_minus='vin', output_plus='sw_out', model='SW', initial_state='off') c.model('SW', 'SW', Ron=1 @ u_mOhm, Roff=100 @ u_MOhm, Vt=1.1 @ u_V) c.X('D1', '1N4148', c.gnd, 'sw_out') c.L(1, 'sw_out', 'output', L) c.R(1, 'output', c.gnd, Rload) c.C(1, 'output', c.gnd, Cout) seq = [(sw_period_cnt, sw_width_cnt)] * 1000 din = drv(t=Tuple[Uint[w_period], Uint[w_period]], seq=seq) \ | pulse \ | flatten \ | Float din = din * int(Vpulse) dout = din | ngspice(f=buck_converter, init_x=0) dout | scope dout | shred verilate('/pulse') sim(timeout=4000, check_activity=False)
def test_mapped_directed(sim_cls, din_delay, cfg_delay, dout_delay, branches): t_ctrl = Uint[bitw(branches - 1)] ref = [(i, i) for i in range(branches)] mapping = {} for i in range(branches): mapping[i] = (i + 1) if (i + 1) < branches else 0 ctrl = list(range(branches)) seqs = [[(i - 1) if (i - 1) >= 0 else (branches - 1)] for i in range(branches)] drvs = [ drv(t=Uint[s[0] + 1], seq=s) | delay_rng(din_delay, din_delay) for s in seqs ] directed(drv(t=t_ctrl, seq=ctrl) | delay_rng(cfg_delay, cfg_delay), *drvs, f=mux(mapping=mapping, sim_cls=sim_cls), delays=[delay_rng(dout_delay, dout_delay)], ref=ref) sim()
async def qdeal_impl_same_lvl(din: Queue, *, num, lvl=b'din.lvl-1') -> b'Union[(din, ) * num]': for i in range(num): async for (data, eot) in din: d = data if lvl == 0 else (data, eot) yield (d, trunc(i, Uint[bitw(num - 1)]))
async def test(din: Array[Maybe, 'num']) -> b'Array[Uint[bitw(num-1)], num]': num = len(din.dtype) TIndex = Uint[bitw(num - 1)] data = Array[TIndex, num]() async with din as d: cnt = TIndex(0) for i in range(num): data[i] = cnt if d[i].ctrl: cnt += 1 yield data
def ii_gen(din: Queue[Uint['w_din'], 2], *, frame_size=(25, 25)): fifo_depth = 2**bitw(frame_size[1]) accum_s = din | dreg_sp | accum_wrap(add_num=frame_size[0] * frame_size[1]) fifo_out = Intf(accum_s.dtype[0]) add_s = ccat(accum_s[0], fifo_out) | add fifo_in = ccat(add_s, accum_s[1]) | Queue[add_s.dtype, 2] fifo_out |= fifo_in | decouple | flatten | fifo2( depth=fifo_depth, preload=frame_size[1], regout=False) ii_s = fifo_in return ii_s | dreg_sp
async def qdeal_same_lvl(din: Queue, *, num, lvl=b'din.lvl-1') -> b'(din, ) * num': i = Uint[bitw(num)](0) while i != num: async for (data, eot) in din: dout = data if lvl == 0 else (data, eot) yield demux(i, dout, use_dflt=False, mapping={n: n for n in range(num)}) i += 1
def schedule(block, ctx): ctx.scope['_rst_cond'] = ir.Variable('_rst_cond', Bool) block.stmts.insert( 0, ir.AssignValue(ctx.ref('_rst_cond', 'store'), res_false)) block.stmts.append( ir.AssignValue(ctx.ref('_rst_cond', 'store'), res_true)) Scheduler(ctx).visit(block) # print('*** Schedule ***') # print(PPrinter(ctx).visit(block)) state_num = len(block.state) if state_num > 1: ctx.scope['_state'] = ir.Variable( '_state', val=ir.ResExpr(Uint[bitw(state_num - 1)](0)), reg=True, ) stateblock = ir.IfElseBlock(stmts=[]) for i in range(state_num): v = StateIsolator(ctx, i) res = v.visit(block) if isinstance(res, list): res = ir.HDLBlock(stmts=res) res.exit_cond = res_false stateblock.stmts.append(res) if state_num > 1: res.in_cond = ir.BinOpExpr((ctx.ref('_state'), ir.ResExpr(i)), ir.opc.Eq) if state_num > 1: modblock = ir.CombBlock(stmts=[stateblock]) else: modblock = ir.CombBlock(stmts=stateblock.stmts[0].stmts) modblock = infer_cycle_done(modblock, ctx) return modblock
async def qdeal_impl( din: Queue, *, num, lvl=b'din.lvl-1') -> b'Union[(Queue[din.data, din.lvl-1], ) * num]': i = Uint[bitw(num - 1)](0) async for (data, eot) in din: out_eot = eot[:lvl] d = data if lvl == 0 else (data, out_eot) yield (d, i) if all(out_eot): if i == (num - 1): i = 0 else: i += 1
async def test(din, *, chunk_len, num_workers) -> b'din': counter = Uint[bitw(chunk_len * chunk_len)](0) chunk_pow = chunk_len * chunk_len async for arr, last_arr in din: if counter >= chunk_pow: counter = 0 if not last_arr: yield arr, last_arr counter += 1 if last_arr: if counter == chunk_pow - 1: yield arr, last_arr else: yield arr, Uint[1](0) counter += 1 while counter < chunk_pow - 1 and last_arr: yield [[0] * chunk_len] * num_workers, Uint[1](0) counter += 1 yield [[0] * chunk_len] * num_workers, Uint[1](1)
async def qdeal(din: Queue, *, num, lvl=b'din.lvl-1') -> b'(Queue[din.data, din.lvl-1], ) * num': i = Uint[bitw(num)](0) async for (data, eot) in din: out_eot = eot[:lvl] dout = data if lvl == 0 else (data, out_eot) yield demux(i, dout, use_dflt=False, mapping={n: n for n in range(num)}) if all(out_eot): if i == (num - 1): i = 0 else: i += 1
async def serialize_plain(din) -> Queue['din[0]']: i = Uint[bitw(len(din.dtype) - 1)](0) async with din as val: for i, last in qrange(len(din.dtype)): yield val[i], last
def schedule(cfg, ctx): ctx.scope['_state'] = ir.Variable( '_state', val=ir.ResExpr(Uint[1](0)), reg=True, ) loops = [] LoopBreaker(ctx, loops).visit(cfg) v = ReachingNodes() v.visit(cfg) reaching_nodes = v.reaching state_cfg = {0: cfg} isolated_loops = {} for l in loops: isolated_loops[l.value.state_id] = isolate(ctx, l) state_in_scope = [{} for _ in range(1 + len(loops))] piggied = set() i = 0 order = list(state_cfg.keys()) while i < len(order): state_id = order[i] cfg = state_cfg[state_id] # print(f'[{state_id}]: Scoping') new_states = {} # print_cfg_ir(cfg) if loops: non_local, piggied_cur = discover_piggieback_states(cfg, ctx, state_in_scope[state_id], state_id, reaching_nodes, state_cfg) VarScope(ctx, state_in_scope, state_id, new_states).visit(cfg) cfg.value.states.append(state_id) if loops: for nl in non_local: state_cfg[nl] = isolated_loops[nl] order.insert(i + 1, nl) cfg.value.states.extend(piggied_cur) piggied.update(piggied_cur) state_num = len(state_in_scope) - len(new_states) if new_states: # print(f'[{state_id}]: Isolating') state_cfg[state_id] = isolate(ctx, cfg, exits=new_states, state_num=state_num) # draw_scheduled_cfg(state_cfg[state_id], simple=False) # print_cfg_ir(state_cfg[state_id]) for si, ns in enumerate(new_states): new_state_id = state_num + si # order.insert(i + 1, len(state_cfg)) # print(f'[{len(state_cfg)}]: Isolating') # state_cfg.append(isolate(ctx, ns)) order.insert(i + 1, new_state_id) # print(f'[{len(state_cfg)}]: Isolating') state_cfg[new_state_id] = isolate(ctx, ns) # draw_scheduled_cfg(state_cfg[new_state_id], simple=False) i += 1 if i == len(order): missing = (piggied | state_cfg.keys()) ^ set(range(len(state_in_scope))) for s in missing: # TODO: Can this really be done after all stmts have been inlined? state_cfg[s] = isolated_loops[s] order.append(s) for i, s in state_cfg.items(): in_scope = state_in_scope[i] # draw_scheduled_cfg(s, simple=True) # draw_scheduled_cfg(s, simple=False) append_state_epilog(s, ctx) prepend_state_prolog(s, ctx, in_scope) ResolveBlocking(ctx).visit(s) # print_cfg_ir(s) RebuildStateIR().visit(s) # print(f'------------- State {i} --------------') # print_cfg_ir(s) states = {i: s.value for i, s in state_cfg.items()} for i, s in states.items(): test = ir.res_false for j in s.states: state_test = ir.BinOpExpr((ctx.ref('_state'), ir.ResExpr(j)), ir.opc.Eq) test = ir.BinOpExpr([test, state_test], ir.opc.Or) # state_num = len(states) state_num = len(state_in_scope) ctx.scope['_state'].val = ir.ResExpr(Uint[bitw(state_num - 1)](0)) ctx.scope['_state'].dtype = Uint[bitw(state_num - 1)] stateblock = ir.HDLBlock() for i, s in states.items(): test = ir.res_false for j in s.states: state_test = ir.BinOpExpr((ctx.ref('_state'), ir.ResExpr(j)), ir.opc.Eq) test = ir.BinOpExpr([test, state_test], ir.opc.Or) stateblock.add_branch(ir.Branch(stmts=s.stmts, test=test)) modblock = ir.Module(stmts=[stateblock]) return modblock