def test_add_migen(self): test_template1 = NodeTemplate(name="test_1", inputs=[('a', DOptional(int)), ('b', DOptional(int))]) test_template1.add_constructor(AMigenNode2()) with DeltaGraph(): n1 = test_template1.call(2, 3) self.assertEqual(len(n1.bodies), 1) self.assertIn(PyMigenBody, n1.body.access_tags)
def test_via_migen_init(self): m_template = NodeTemplate(name="MTemplate", inputs=[('a', DOptional(int)), ('b', DOptional(int))]) @DeltaBlock(m_template, allow_const=False) def m_simple_add(a: DOptional(int), b: DOptional(int)): raise DeltaRuntimeExit m_maker = AMigenNode(node_template=m_template) with DeltaGraph(): n1 = m_maker.call(a=1, b=3) self.assertEqual(len(n1.bodies), 2) self.assertIn(PyMigenBody, n1.body.access_tags)
def setUp(self): # obligatory and optional ports out_port_obl = OutPort( NamespacedName("port_name", None), DInt(), InPort(NamespacedName("port_name", None), DInt(), None, 0), None ) out_port_opt = OutPort( NamespacedName("port_name", None), DInt(), InPort(NamespacedName("port_name", None), DOptional(DInt()), None, 0), None ) # 4 types of queues self.delta_queue_obl = DeltaQueue(out_port_obl) self.delta_queue_opt = DeltaQueue(out_port_opt) self.const_queue_obl = ConstQueue(out_port_obl) self.const_queue_opt = ConstQueue(out_port_opt) # test messages self.msg1 = QueueMessage(1) self.msg2 = QueueMessage(2) self.msg_with_none = QueueMessage(None) self.msg_unpackable = QueueMessage("abcde") # these messages should be received self.msg1_answer = QueueMessage(1) self.msg2_answer = QueueMessage(2) self.msg_with_none_answer = QueueMessage(None)
def test_add_migen(self): test_template1 = NodeTemplate(name="test_1", inputs=[('a', DOptional(int)), ('b', DOptional(int))]) class AMigenNode(MigenNodeTemplate): def migen_body(self, template): template.add_pa_in_port('a', DOptional(int)) template.add_pa_in_port('b', DOptional(int)) with DeltaGraph(): n1 = test_template1.call(a=2, b=3) self.assertEqual(len(n1.bodies), 0) n1.add_body(AMigenNode()) self.assertEqual(len(n1.bodies), 1) self.assertIn(PyMigenBody, n1.body.access_tags)
def test_in_port_capnp_optional(self): """Generate optional in port.""" in_port = InPort(NamespacedName("node_name", "index"), DOptional(int), None, 0) capnp_in_port = dotdf_capnp.InPort.new_message() in_port.capnp(capnp_in_port) self.assertEqual(capnp_in_port.name, "index") self.assertEqual(dill.loads(capnp_in_port.type), DInt()) self.assertEqual(capnp_in_port.optional, True)
def migen_body(self, template): # Input/Outputs start here: # 2 inputs and 2 outputs. # # This block group ports which will be accessed by migen, using # the protocol adapters. # in_ports and out_ports implement a similar logic based on 3 # signals, ready, valid and data. # An input can be received when the ready signal is = '1'. # data contains the value of the message that we are receiving # and can considered sensible only when valid = '1', i.e. when # a new data has been received on the pa_input_port. # The opposite logic holds true for the outputs. in1 = template.add_pa_in_port('in1', DOptional(int)) in2 = template.add_pa_in_port('in2', DOptional(int)) out1 = template.add_pa_out_port('out1', int) out2 = template.add_pa_out_port('out2', int) # The main migen logic starts here: # Everything below is just an example that show different routines. # Add a 32-bit counter (0-2**32-1) which will increment at each clock # cycle. self.counter = migen.Signal(32) self.sync += self.counter.eq(self.counter + 1) # Add a condition when in_ports are ready. self.comb += migen.If(self.counter >= 3, in1.ready.eq(1), in2.ready.eq(1)) # Pretend that we do a useful calculations. # Here we first check that the outputs are ready. # Then wait for the counter to reach 100. # And write outputs. # Note that the output should be marked as valid. self.comb += migen.If( (out1.ready & out2.ready) == 1, migen.If(self.counter == 5, out1.data.eq(in1.data + in2.data), out2.data.eq(self.counter), out1.valid.eq(in1.valid & in2.valid), out2.valid.eq(in1.valid & in2.valid)).Else( out1.valid.eq(0), out2.valid.eq(0)))
def migen_body(self, template): # inputs and 1 output in1 = template.add_pa_in_port('in1', DOptional(int)) out1 = template.add_pa_out_port('out1', DOptional(int)) # Counter self.incremented = migen.Signal(10) # for instance, at this clock the node is ready to input self.comb += in1.ready.eq(1) self.sync += migen.If( out1.ready == 1, migen.If(in1.valid, out1.data.eq(self.incremented), out1.valid.eq(0x1), self.incremented.eq(in1.data+1) ).Else(out1.valid.eq(0)) )
def test_inputs_enforced_optional(self): """Test to ensure in params must match when associating constructors with a NodeTemplate """ test_template2 = NodeTemplate(name="test", inputs=[('a', DOptional(int)), ('b', DOptional(int))], outputs=int) with self.assertRaises(ValueError): @DeltaBlock(test_template2, allow_const=False) def _test1(a: DOptional(int), b: int) -> int: return a + b with self.assertRaises(ValueError): @DeltaBlock(test_template2, allow_const=False) def _test2(wrong_name: int, b: int) -> int: return wrong_name + b
def test_node_serialisation_multi_body_node(self): """If two blocks share the same body only keep one copy.""" with DeltaGraph() as test_graph: n1 = self.func(2, 3) @DeltaBlock(allow_const=False) def over_complex_add(a: DOptional(int), b: DOptional(int)): raise DeltaRuntimeExit @Interactive(inputs=[('a', DOptional(int)), ('b', DOptional(int))]) def broken_adder(node: RealNode): node.receive('a') node.receive('b') raise DeltaRuntimeExit n1.add_body(AMigenNode()) n1.add_body(over_complex_add) n1.add_body(OpCacher().cached_add) n1.add_body(broken_adder) _, prog = serialize_graph(test_graph) self.assertEqual(len(prog.nodes[2].bodies), 5)
def migen_body(self, template): start = template.add_pa_in_port('start', DOptional(int)) out_a = template.add_pa_out_port('out_a', int) out_b = template.add_pa_out_port('out_b', int) # This will need to be converted to boolean when migen nodes support # boolean self.cnt = migen.Signal(10) self.comb += (out_a.ready.eq(1), out_b.ready.eq(1), start.ready.eq(1)) self.sync += migen.If(self.cnt & 0x1, out_a.valid.eq(start.data), out_b.valid.eq(0)).Else( out_a.valid.eq(0), out_b.valid.eq(start.data)) self.sync += (self.cnt.eq(self.cnt + 1), out_a.data.eq(self.cnt), out_b.data.eq(self.cnt))
def migen_body(self, template): inp = template.add_pa_in_port('inp', DOptional(DInt())) trigger = template.add_pa_in_port('trigger', DOptional(DInt())) out = template.add_pa_out_port('out', DInt()) # Declare input and output ports always happy to receive/transmit data self.comb += ( inp.ready.eq(1), trigger.ready.eq(1), out.ready.eq(1), ) commander_fsm = FSM(reset_state="IDLE") self.submodules.commander_fsm = commander_fsm commander_fsm.act("IDLE", If(inp.valid == 1, NextState("LOADING"))) commander_fsm.act( "LOADING", If(trigger.valid & trigger.data == 1, NextState("RETURN")).Else( NextValue(out.data, out.data + inp.data), )) commander_fsm.act("RETURN", NextValue(out.valid, 1), NextState("IDLE"))
def cached_add(self, a: DOptional(int), b: DOptional(int)): if (a, b) not in self._add_cache: self._add_cache[(a, b)] = a + b raise DeltaRuntimeExit
def test_DOptional(self): port = OutPort(NamespacedName("test_name", None), DOptional(DInt()), None, None) with self.assertRaises(TypeError): dummy = port.port_type
def test_DOptiona_of_DUnion(self): port = InPort(NamespacedName("test_name", None), DOptional(DUnion([DInt(), DFloat()])), None, 0) self.assertEqual(port.port_type, DUnion([DInt(), DFloat()])) self.assertEqual(port.is_optional, True)
def test_DOptional(self): port = InPort(NamespacedName("test_name", None), DOptional(DInt()), None, 0) self.assertEqual(port.port_type, DInt()) self.assertEqual(port.is_optional, True)
def add(a: int, b: DOptional(int)) -> int: if b is None: return a else: return a + b
def _test1(a: DOptional(int), b: int) -> int: return a + b
def migen_body(self, template): template.add_pa_in_port('a', DOptional(int)) template.add_pa_in_port('b', DOptional(int))
def add_print_exit(a: DOptional(int), b: DOptional(int)) -> Void: print(a + b) raise DeltaRuntimeExit
def simple_add_2(a: DOptional(int), b: DOptional(int)): raise DeltaRuntimeExit
def over_complex_add(a: DOptional(int), b: DOptional(int)): raise DeltaRuntimeExit