def test_union(self): union_mix = dl.Union([ dl.Int(dl.Size(16)), dl.Bool(), dl.Str(dl.Size(10)), dl.Tuple([ dl.Int(dl.Size(8)), dl.UInt(dl.Size(16)), dl.Float(dl.Size(64)), dl.Complex(dl.Size(128)), dl.Bool(), dl.Str(dl.Size(10)) ]), dl.Record(RecATI) ]) @dl.Interactive([("ack_union_mix", bool)], [("out_union_mix", union_mix)]) def testbench(node: dl.PythonNode): node.send(out_union_mix=5) assert node.receive("ack_union_mix") node.send(out_union_mix=False) assert node.receive("ack_union_mix") node.send(out_union_mix='abcd') assert node.receive("ack_union_mix") node.send(out_union_mix=(-5, 10, -1.5, (1.5 + 2.5j), False, 'hello')) assert node.receive("ack_union_mix") node.send(out_union_mix=RecATI([1, 2], (3.0, 4), 5)) assert node.receive("ack_union_mix") raise DeltaRuntimeExit s_union_mix = dl.lib.StateSaver(union_mix, verbose=True) with dl.DeltaGraph() as graph: p = dl.placeholder_node_factory() p.specify_by_node( testbench.call(s_union_mix.save_and_ack(p.out_union_mix))) self.check_executes_graph( graph, """\ saving 5 saving False saving abcd saving (-5, 10, -1.5, (1.5+2.5j), False, 'hello') saving RecATI(x=[1, 2], y=(3.0, 4), z=5) """)
def test_compound(self): tuple_mix = dl.Tuple([ dl.Int(dl.Size(8)), dl.UInt(dl.Size(16)), dl.Float(dl.Size(64)), dl.Complex(dl.Size(128)), dl.Bool(), dl.Str(dl.Size(10)) ]) array_float = dl.Array(dl.Float(dl.Size(64)), dl.Size(3)) record_mix = dl.Record(RecATI) @dl.Interactive([("ack_tuple_mix", bool), ("ack_array_float", bool), ("ack_record_mix", bool)], [("out_tuple_mix", tuple_mix), ("out_array_float", array_float), ("out_record_mix", record_mix)]) def testbench(node: dl.PythonNode): node.send(out_tuple_mix=(-5, 1000, -100.5, (1.5 + 2.5j), False, '0123456789')) assert node.receive("ack_tuple_mix") node.send(out_array_float=[0.5, -0.25, 0.125]) assert node.receive("ack_array_float") node.send(out_record_mix=RecATI([1, 2], (3.0, 4), 5)) assert node.receive("ack_record_mix") raise DeltaRuntimeExit s_tuple_mix = dl.lib.StateSaver(tuple_mix, verbose=True) s_array_float = dl.lib.StateSaver(array_float, verbose=True) s_record_mix = dl.lib.StateSaver(record_mix, verbose=True) with dl.DeltaGraph() as graph: p = dl.placeholder_node_factory() p.specify_by_node( testbench.call(s_tuple_mix.save_and_ack(p.out_tuple_mix), s_array_float.save_and_ack(p.out_array_float), s_record_mix.save_and_ack(p.out_record_mix))) self.check_executes_graph( graph, """\ saving (-5, 1000, -100.5, (1.5+2.5j), False, '0123456789') saving [0.5, -0.25, 0.125] saving RecATI(x=[1, 2], y=(3.0, 4), z=5) """)
def testbench(node): data_array = generate_data_vector(C_N_BITS, C_N_INPUTS) # Temporary - needs df.Array => migen.Array support data_vector = 0 logging.debug(f'data sent to DUT {data_array}') for i in range(C_N_INPUTS): data_vector += data_array[i] << C_N_BITS * i data_vector = dl.Int(dl.Size(C_VECTOR_LEN)).from_numpy_object(data_vector) for cmd in range(0x01, 0x06): node.send(data=data_vector, cmd=cmd) result = node.receive('result') error = node.receive('error') logging.debug(f'cmd: {cmd}') exp_err = 0 if cmd == Commands.MIN: exp_res = np.min(data_array) logging.debug(f'result: {result}, expected: {exp_res}') assert result == exp_res elif cmd == Commands.MAX: exp_res = np.max(data_array) logging.debug(f'result: {result}, expected: {exp_res}') assert result == exp_res elif cmd == Commands.SUM: exp_res = np.sum(data_array) logging.debug(f'result: {result}, expected: {exp_res}') assert result == exp_res elif cmd == Commands.AVG: exp_res_low = trunc(np.mean(data_array)) - 1 exp_res_high = int(np.mean(data_array)) + 1 exp_res = np.mean(data_array) logging.debug(f'result: {result}, expected: {exp_res}') assert result >= exp_res_low assert result <= exp_res_high else: exp_err = 1 result = -1 exp_res = -1 assert error == exp_err raise dl.DeltaRuntimeExit
self.sync += migen.If( i1.valid == 1, o1.valid.eq(1), o1.data.eq(i1.data+1) ).Else( o1.data.eq(0), migen.If(started == 0, o1.valid.eq(1), started.eq(1) ).Else( o1.valid.eq(0) ) ) @dl.Interactive([("measurement", dl.UInt(dl.Size(32)))], [("output", dl.UInt(dl.Size(32)))], name="interactive_simple") def send_gates_list_then_exit(node: dl.PythonNode): cmds = ["RX", "RZ", "RY"] # for non-deterministic tests use random.randint(0, 255) args = [99, 250, 11] node.send(dl.lib.command_creator("STATE_PREPARATION")) for cmd, arg in zip(cmds, args): node.send(dl.lib.command_creator(cmd, argument=arg)) node.send(dl.lib.command_creator("STATE_MEASURE")) measurement = node.receive("measurement") print(f"Measurement: {measurement}")
def test_primitives(self): tuple_int = dl.Tuple([ dl.Int(dl.Size(8)), dl.Int(dl.Size(16)), dl.Int(dl.Size(32)), dl.Int(dl.Size(64)) ]) tuple_uint = dl.Tuple([ dl.UInt(dl.Size(8)), dl.UInt(dl.Size(16)), dl.UInt(dl.Size(32)), dl.UInt(dl.Size(64)) ]) tuple_float = dl.Tuple([dl.Float(dl.Size(32)), dl.Float(dl.Size(64))]) tuple_complex = dl.Tuple( [dl.Complex(dl.Size(64)), dl.Complex(dl.Size(128))]) tuple_bool_char = dl.Tuple([dl.Bool(), dl.Str(dl.Size(1))]) @dl.Interactive([("ack_int", bool), ("ack_uint", bool), ("ack_float", bool), ("ack_complex", bool), ("ack_bool_char", bool)], [("out_int", tuple_int), ("out_uint", tuple_uint), ("out_float", tuple_float), ("out_complex", tuple_complex), ("out_bool_char", tuple_bool_char)]) def testbench(node: dl.PythonNode): node.send(out_int=(-128, -32768, -2147483648, -9223372036854775808)) assert node.receive("ack_int") node.send(out_int=(127, 32767, 2147483647, 9223372036854775807)) assert node.receive("ack_int") node.send(out_uint=(0, 0, 0, 0)) assert node.receive("ack_uint") node.send(out_uint=(255, 65535, 4294967295, 18446744073709551615)) assert node.receive("ack_uint") # this is just a rough estimate node.send(out_float=(1.0000001, 1.000000000000001)) assert node.receive("ack_float") node.send(out_complex=((1.0000001 + 1.0000001j), (1.000000000000001 + 1.000000000000001j))) assert node.receive("ack_complex") node.send(out_bool_char=(True, 'a')) assert node.receive("ack_bool_char") raise DeltaRuntimeExit s_int = dl.lib.StateSaver(tuple_int, verbose=True) s_uint = dl.lib.StateSaver(tuple_uint, verbose=True) s_float = dl.lib.StateSaver(tuple_float, verbose=True) s_complex = dl.lib.StateSaver(tuple_complex, verbose=True) s_bool_char = dl.lib.StateSaver(tuple_bool_char, verbose=True) with dl.DeltaGraph() as graph: p = dl.placeholder_node_factory() p.specify_by_node( testbench.call(s_int.save_and_ack(p.out_int), s_uint.save_and_ack(p.out_uint), s_float.save_and_ack(p.out_float), s_complex.save_and_ack(p.out_complex), s_bool_char.save_and_ack(p.out_bool_char))) self.check_executes_graph( graph, f"""\ saving (-128, -32768, -2147483648, -9223372036854775808) saving (127, 32767, 2147483647, 9223372036854775807) saving (0, 0, 0, 0) saving (255, 65535, 4294967295, 18446744073709551615) saving ({np.float32(1.0000001)}, 1.000000000000001) saving (({np.float32(1.0000001)}+{np.float32(1.0000001)}j), (1.000000000000001+1.000000000000001j)) saving (True, 'a') """)
def migen_body(self, template): # generics N_BITS = template.generics["N_BITS"] # 1-64 N_INPUTS = template.generics["N_INPUTS"] TREE_DEPTH = int(ceil(log2(N_INPUTS))) # inputs self.d_in = template.add_pa_in_port( 'd_in', dl.Optional(dl.Int(dl.Size(N_BITS * N_INPUTS)))) self.cmd = template.add_pa_in_port('cmd', dl.Optional(dl.Int())) # outputs self.d_out = template.add_pa_out_port('d_out', dl.Int()) self.err = template.add_pa_out_port('error', dl.Int()) # input length correction [need a power of 2 sized tree] N_INPUTS_CORR = pow(2, TREE_DEPTH) # internals # correct the size of the input tree to be a power of 2 # and register the inputs self.d_in_full_reg = Signal(N_INPUTS_CORR * N_BITS) self.d_in_valid_reg = Signal(1) self.cmd_data_reg = Signal(8) self.cmd_valid_reg = Signal(1) # register outputs self.d_out_data_reg = Signal(N_BITS + TREE_DEPTH) self.d_out_valid_reg = Signal(1) self.err_data_reg = Signal(1) self.err_valid_reg = Signal(1) # create the 2D array of data [INPUTS x TREE_DEPTH] to route # all the core units in an iterative way. The number of bits is incremented # at each stage to account for the carry in additions. self.d_pipe = Array( Array(Signal(N_BITS + b) for a in range(N_INPUTS_CORR)) for b in range(TREE_DEPTH + 1)) # create the 2D array of error signals. self.e_pipe = Array( Array(Signal(N_BITS) for a in range(N_INPUTS_CORR)) for b in range(TREE_DEPTH)) ### # correct input vector length to match a power of 2. # fill non-provided inputs with 0's (affects mean and minimum) self.sync += [ self.d_in_full_reg.eq(self.d_in.data), self.d_in_valid_reg.eq(self.d_in.valid), self.cmd_data_reg.eq(self.cmd.data), self.cmd_valid_reg.eq(self.cmd.valid) ] # wiring inputs to the first stage of the tree for i in range(N_INPUTS_CORR): self.comb += [ self.d_pipe[0][i].eq(self.d_in_full_reg[N_BITS * i:N_BITS * (i + 1)]) ] # instantiation of the core units. for j in range(TREE_DEPTH): for i in range(int(N_INPUTS_CORR / (pow(2, j + 1)))): self.submodules += CoreUnit(self.d_pipe[j][2 * i], self.d_pipe[j][2 * i + 1], self.d_pipe[j + 1][i], self.cmd_data_reg, self.e_pipe[j][i], N_BITS) # error signal propagation. If any of the single units have # a high error signal, the error is propagated to the node's output. self.comb += [ If(self.e_pipe[j][i] == 1, self.err_data_reg.eq(1)) ] self.comb += [ self.d_in.ready.eq(1), self.cmd.ready.eq(1), self.d_out_data_reg.eq(self.d_pipe[TREE_DEPTH][0]), If(self.d_in_valid_reg, self.err_valid_reg.eq(1), self.d_out_valid_reg.eq(1)).Else(self.err_valid_reg.eq(0)) ] self.sync += [ self.d_out.data.eq(self.d_out_data_reg), self.d_out.valid.eq(self.d_out_valid_reg), self.err.data.eq(self.err_data_reg), self.err.valid.eq(self.err_valid_reg) ]
def experiment_stopper(completed: dl.Int(dl.Size(8))) -> dl.Void: raise dl.DeltaRuntimeExit
self.sync += [ self.d_out.data.eq(self.d_out_data_reg), self.d_out.valid.eq(self.d_out_valid_reg), self.err.data.eq(self.err_data_reg), self.err.valid.eq(self.err_valid_reg) ] def generate_data_vector(N_BITS, N_INPUTS): return np.random.randint(0, pow(2, N_BITS), size=N_INPUTS) @dl.Interactive(inputs=[('result', dl.Int()), ('error', dl.Int())], outputs=[('cmd', dl.Int()), ('data', dl.Int(dl.Size(C_VECTOR_LEN)))]) def testbench(node): data_array = generate_data_vector(C_N_BITS, C_N_INPUTS) # Temporary - needs df.Array => migen.Array support data_vector = 0 logging.debug(f'data sent to DUT {data_array}') for i in range(C_N_INPUTS): data_vector += data_array[i] << C_N_BITS * i data_vector = dl.Int(dl.Size(C_VECTOR_LEN)).from_numpy_object(data_vector) for cmd in range(0x01, 0x06): node.send(data=data_vector, cmd=cmd) result = node.receive('result') error = node.receive('error')
def migen_body(self, template): template.add_pa_in_port('i', dl.Optional(dl.Int(dl.Size(8))))
def method_func_no_output(self, i: dl.Int(dl.Size(8))) -> dl.Void: print(i + 1)
def multi_body_no_output(i: dl.Int(dl.Size(8))) -> dl.Void: print(i)
def forked_return_output(x: dl.Int(dl.Size(8)), y: dl.Int(dl.Size(8)) ) -> Tuple[int, bool, int, int]: return 0, 1, 1, 0
class Foo(): def __init__(self): pass @dl.DeltaMethodBlock() def method_func_no_output(self, i: dl.Int(dl.Size(8))) -> dl.Void: print(i + 1) class MigenFoo(dl.MigenNodeTemplate): def migen_body(self, template): template.add_pa_in_port('i', dl.Optional(dl.Int(dl.Size(8)))) @dl.Interactive([('i', dl.Int(dl.Size(8)))]) def interactive_func_no_output(node: dl.RealNode): node.receive('i') template_no_output_no_body = dl.NodeTemplate( name="template_no_output_no_body", inputs=[('i', dl.Int(dl.Size(8)))] ) @dl.DeltaBlock() def experiment_stopper(completed: dl.Int(dl.Size(8))) -> dl.Void: raise dl.DeltaRuntimeExit