def ufixp_value_trunc_resolver(trunc_type: UfixpType, val): if type(val).fract > trunc_type.fract: return trunc_type.decode( code(val, int) >> (type(val).fract - trunc_type.fract)) else: return trunc_type.decode( code(val, int) << (trunc_type.fract - type(val).fract))
def qround(din, *, fract=0, cut_bits=b'get_cut_bits(din, fract)', signed=b'din.signed') -> b'get_out_type(din, fract)': res = code(din, Int if signed else Uint) + (Bool(1) << (cut_bits - 1)) return code(res >> cut_bits, module().tout)
async def test(din: Bool, *, w_dout) -> Uint['w_dout']: data = Array[Bool, w_dout](None) async with din as d: for i in range(w_dout): data[i] = d yield code(data, Uint)
def __new__(cls, operand, cast_to): if isinstance(cast_to, ResExpr): cast_to = cast_to.val if cast_to == int: cast_to = Uint[operand.dtype.width] if operand.dtype == cast_to: return operand if isinstance(operand, ResExpr): return ResExpr(code(operand.val, cast_to)) if isinstance(operand, ConcatExpr) and typeof( cast_to, (Array, Tuple, Queue, Union)): cast_ops = [ CastExpr(op, cast_t) if op.dtype != cast_t else op for op, cast_t in zip(operand.operands, cast_to) ] operand = ConcatExpr(cast_ops) inst = super().__new__(cls) inst.operand = operand inst.cast_to = cast_to return inst
def visit_ResExpr(self, node): if isinstance(node.val, tuple): res = [] for op in reversed(node.val): res_op = ir.ResExpr(op) if res_op != ir.ResExpr(Unit()) and res_op.dtype != Uint[0]: svexpr = self.visit(res_op) res.append(self.cast_svexpr(svexpr, res_op.dtype, type(op))) if not res: return None return '{' + ', '.join(res) + '}' if getattr(node.val, 'unknown', False): return f"{node.dtype.width}'bx" val = node.val if isinstance(node.val, ir.EmptyType): if node.dtype is None: return f"'x" else: return f"{node.dtype.width}'bx" elif not isinstance(node.val, Integer): val = Integer(code(node.val, int)) sign = '-' if val < 0 else '' return f"{sign}{val.width}'d{abs(int(val))}"
async def iceil(din: Uint['T'], *, div=4) -> Uint['T']: """Performs division of the input value and return the ceiling of the calculated value Args: div: The divisor value """ async with din as val: yield code((val + div - 1) // div, din.dtype)
async def test(din: Uint[4]) -> Uint[4]: c = Uint[4](0) while c[:1] == 0: async with din as c: yield c c = Uint[4](0) while c[:1] == 0: async with din as c: yield code(2 * c, Uint[4])
async def qrange_stop_inclusive(stop: Integer, *, inclusive) -> Queue[b'stop']: cnt = stop.dtype(0) last: Bool async with stop as s: last = False while not last: last = cnt == s yield cnt, last cnt = code(cnt + 1, stop.dtype)
def int_value_trunc_resolver(trunc_type: IntType, val): bv = code(val, int) sign = bv >> (type(val).width - 1) if trunc_type.width <= type(val).width: bv_res = bv & ((1 << trunc_type.width) - 1) \ | (sign << (trunc_type.width - 1)) else: sign_exten = Uint[trunc_type.width - type(val).width].max if sign else 0 bv_res = (sign_exten << type(val).width) | bv return trunc_type.decode(bv_res)
async def sot_queue(din: Queue['data', 'lvl'], *, lvl=b'lvl') -> Tuple[b'din.data', b'din.eot']: sot = din.dtype.eot.max async for (data, eot) in din: yield (data, sot) neot = (~eot) << 1 sot_arr = Array[Uint[1], lvl](None) for i in range(lvl): sot_arr[i] = eot[i] if i == 0 else sot[i] & neot[i] sot = code(sot_arr, Uint)
def params(self): if not self.impl_params: return {} params = {} for k, v in self.node.params.items(): param_name = k.upper() param_valid_name = f'{param_name}_VALID' if (param_name in self.impl_params): if v is None: if param_valid_name in self.impl_params: params[param_valid_name] = 0 continue if is_type(v): v = max(v.width, 1) err = None try: v = code(v, int) except: err = ValueError( f'Cannot encode value "{v}" as integer, passed for HDL parameter "{param_name}"\n' f' - when instantiating module "{self.node.name}"') if err: raise err if (code(v, int) != int(self.impl_params[param_name]['val'])): params[param_name] = code(v, int) if param_valid_name in self.impl_params: params[param_valid_name] = 1 return params
def fixp_value_trunc_resolver(trunc_type: FixpType, val): bv = code(val, Uint) sign = bv >> (type(val).width - 1) if type(val).fract >= trunc_type.fract: bv_fract_trunc = bv >> (type(val).fract - trunc_type.fract) else: bv_fract_trunc = bv << (trunc_type.fract - type(val).fract) if type(val).integer >= trunc_type.integer: bv_res = (bv_fract_trunc & ((1 << (trunc_type.width - 1)) - 1) | (sign << (trunc_type.width - 1))) else: sign_exten = Uint[trunc_type.integer - type(val).integer].max if sign else 0 bv_res = (sign_exten << (type(val).integer + trunc_type.fract)) | bv_fract_trunc return trunc_type.decode(bv_res)
async def cordic_stage_hls(din, *, i, cordic_angle, ww, pw) -> b'din': async with din as (xv, yv, ph): if i + 1 < ww: xv_shift = (xv >> (i + 1)) yv_shift = (yv >> (i + 1)) else: xv_shift = Uint[1](0) yv_shift = Uint[1](0) pol = ph[-1] if pol: xv_next = code(xv + yv_shift, Int[ww]) yv_next = code(yv - xv_shift, Int[ww]) ph_next = code(ph + cordic_angle, Uint[pw]) else: xv_next = code(xv - yv_shift, Int[ww]) yv_next = code(yv + xv_shift, Int[ww]) ph_next = code(ph - cordic_angle, Uint[pw]) yield (xv_next, yv_next, ph_next)
def add_real_part_func(x: TComplex, y: TComplex) -> b'x[0]': if x[0] % 2: return code(x[0] + y[0], type(x[0])) else: return code(x[1] + y[1], type(x[0]))
def add_real_part_func(x: TComplex, y: TComplex) -> b'x[0]': return code(x[0] + y[0], type(x[0]))
async def add_real_part_module(x: TComplex, y: TComplex) -> b'x[0]': res: x.dtype[0] + y.dtype[0] async with gather(x, y) as data: res = add_real_part_func(data[0], data[1]) yield code(res, x.dtype[0])
async def test(*din: Uint) -> b'din[0]': async with mux(0, *din) as d: yield code(d[0], Uint[4])
def call_code(val, cast_type=ir.ResExpr(Uint)): cast_type = code(val.dtype, cast_type.val) if val.dtype == cast_type: return val return ir.CastExpr(val, cast_to=cast_type)
def test(din, *, t) -> b't': return code(din, t)
def write_module(hdl_data, v_stmts, writer, **kwds): if 'config' not in kwds: kwds['config'] = {} extras = {} separate_conditions(v_stmts, kwds, vexpr) for name, expr in hdl_data.hdl_functions.items(): compiler = VCompiler(name, writer, hdl_data.hdl_locals, **kwds) compiler.visit(expr) extras.update(compiler.extras) for name, expr in hdl_data.regs.items(): writer.line( vgen_signal(expr.dtype, 'reg', f'{name}_reg', 'input', False)) writer.line( vgen_signal(expr.dtype, 'reg', f'{name}_next', 'input', False)) writer.line(f'reg {name}_en;') writer.line() for name, val in hdl_data.in_intfs.items(): writer.line(vgen_intf(val.dtype, name, 'input', False)) writer.line(vgen_signal(val.dtype, 'reg', f'{name}_s', 'input', False)) tmp = vgen_signal(val.dtype, 'wire', f'{name}_s', 'input') writer.line(tmp.split(';', 1)[1]) writer.line(f"assign {name} = {name}_s;") writer.line() for name, expr in hdl_data.variables.items(): writer.block( vgen_signal(expr.dtype, 'reg', f'{name}_v', 'input', False)) writer.line() if 'conditions' in v_stmts: for cond in v_stmts['conditions'].stmts: writer.line(f'wire {cond.target};') writer.line() if hdl_data.regs: writer.line(f'initial begin') for name, expr in hdl_data.regs.items(): writer.line(f" {name}_reg = {int(code(vexpr(expr.val)))};") writer.line(f'end') for name, expr in hdl_data.regs.items(): writer.block(REG_TEMPLATE.format(name, int(code(vexpr(expr.val))))) for name, val in v_stmts.items(): if name != 'variables': compiler = VCompiler(name, writer, hdl_data.hdl_locals, **kwds) compiler.visit(val) extras.update(compiler.extras) else: kwds['separated_visit'] = True for var_name in hdl_data.variables: compiler = VCompiler(f'{var_name}_v', writer, hdl_data.hdl_locals, **kwds) compiler.visit(val) extras.update(compiler.extras) kwds['separated_visit'] = False for func_impl in extras.values(): writer.block(func_impl)
def round_to_fixp(din, t): rounded = din * (2**t.fract) // 1 if rounded == 2**(t.width - 1): rounded -= 1 return code(int(rounded), cast_type=t)
def uint_value_trunc_resolver(trunc_type: UintType, val): return trunc_type.decode(code(val, int) & ((1 << trunc_type.width) - 1))