def test_memblock_with_write_enable_with_equalsign(self): we = pyrtl.Const(1, bitwidth=1) self.output1 <<= self.memory[self.mem_read_address1] self.output2 <<= self.memory[self.mem_read_address2] self.memory[self.mem_write_address] <<= \ pyrtl.MemBlock.EnabledWrite(self.mem_write_data, enable=we) pyrtl.working_block().sanity_check()
def test_with_block_exception(self): pyrtl.set_working_block(self.block_a) with self.assertRaises(pyrtl.PyrtlInternalError): with pyrtl.set_working_block(self.block_b): self.assertIs(pyrtl.working_block(), self.block_b) raise pyrtl.PyrtlInternalError() self.assertIs(pyrtl.working_block(), self.block_a)
def test_memblock_assign_with_extention(self): big_output = pyrtl.Output(self.bitwidth+1, "big_output") big_output <<= self.memory[self.mem_read_address1] self.output1 <<= 1 self.output2 <<= 2 self.memory[self.mem_write_address] <<= self.mem_write_data pyrtl.working_block().sanity_check()
def test_async_check_should_pass_with_select(self): memory = pyrtl.MemBlock( bitwidth=self.bitwidth, addrwidth=self.addrwidth-1, name='memory') self.output1 <<= memory[self.mem_read_address1[0:-1]] pyrtl.working_block().sanity_check()
def test_unknown_wires(self): inp = pyrtl.Input(8, 'inp') out = pyrtl.Output(8, 'out') out <<= inp pyrtl.working_block().wirevector_set.discard(inp) with self.assertRaises(pyrtl.PyrtlInternalError): # sanity_check_net() self.sanity_error("Unknown wires")
def test_async_check_should_pass(self): memory = pyrtl.MemBlock( bitwidth=self.bitwidth, addrwidth=self.addrwidth, name='memory') self.output1 <<= memory[self.mem_read_address1] memory[self.mem_write_address] <<= self.mem_write_data pyrtl.working_block().sanity_check()
def test_async_check_should_pass_with_cat(self): memory = pyrtl.MemBlock( bitwidth=self.bitwidth, addrwidth=self.addrwidth, name='memory') addr = pyrtl.concat(self.mem_read_address1[0], self.mem_read_address2[0:-1]) self.output1 <<= memory[addr] memory[self.mem_write_address] <<= self.mem_write_data pyrtl.working_block().sanity_check()
def test_undriven_net(self): w = pyrtl.WireVector(name='testwire', bitwidth=3) self.assertRaises(pyrtl.PyrtlError, pyrtl.working_block().sanity_check) pyrtl.reset_working_block() r = pyrtl.Register(3) self.assertRaises(pyrtl.PyrtlError, pyrtl.working_block().sanity_check) pyrtl.reset_working_block() o = pyrtl.Output(3) self.assertRaises(pyrtl.PyrtlError, pyrtl.working_block().sanity_check)
def test_invalid_set_wb(self): x = pyrtl.WireVector() y = 1 pyrtl.set_working_block(self.block_a) with self.assertRaises(pyrtl.PyrtlError): pyrtl.set_working_block(x) self.assertEqual(pyrtl.working_block(), self.block_a) with self.assertRaises(pyrtl.PyrtlError): pyrtl.set_working_block(y) self.assertEqual(pyrtl.working_block(), self.block_a)
def test_const_different_bitwidth_1(self): in_w = pyrtl.Input(5) const = pyrtl.Const(23, 5) const_2 = pyrtl.Const(23, 6) wire_1 = in_w + const wire_2 = in_w + const_2 pyrtl.common_subexp_elimination() self.num_net_of_type('+', 2) pyrtl.working_block().sanity_check()
def test_const_values_2(self): in_w = pyrtl.Input(5) const = pyrtl.Const(23, 5) const_2 = pyrtl.Const(23, 5) wire_1 = in_w + const wire_2 = in_w + const_2 pyrtl.common_subexp_elimination() self.num_net_of_type('+', 1) pyrtl.working_block().sanity_check()
def test_with_block_nested(self): self.block_c = pyrtl.Block() pyrtl.set_working_block(self.block_a) self.assertIs(pyrtl.working_block(), self.block_a) with pyrtl.set_working_block(self.block_b): self.assertIs(pyrtl.working_block(), self.block_b) with pyrtl.set_working_block(self.block_c): self.assertIs(pyrtl.working_block(), self.block_c) self.assertIs(pyrtl.working_block(), self.block_b) self.assertIs(pyrtl.working_block(), self.block_a)
def test_2read_1write(self): small_memory = pyrtl.MemBlock(bitwidth=self.bitwidth, addrwidth=self.addrwidth, name='small_memory', max_read_ports=2, max_write_ports=1) temp = small_memory[self.mem_read_address1] # read temp2 = small_memory[self.mem_read_address2] # read self.output1 <<= temp self.output2 <<= temp2 small_memory[self.mem_write_address] <<= pyrtl.Const(6) # write pyrtl.working_block().sanity_check()
def test_valid_slices(self): self.valid_slice(8, slice(6)) self.valid_slice(8, slice(1, 4)) self.valid_slice(8, slice(1, 8)) # Yes, supplying a end index out of bounds is valid python self.valid_slice(8, slice(1, 2, 2)) self.valid_slice(8, slice(1, 4, 2)) self.valid_slice(8, slice(7, 1, -2)) self.valid_slice(8, slice(-2)) self.valid_slice(8, slice(-6, -2, 3)) pyrtl.working_block().sanity_check()
def test_async_check_should_notpass_with_add(self): memory = pyrtl.MemBlock( bitwidth=self.bitwidth, addrwidth=self.addrwidth, name='memory') addr = pyrtl.WireVector(self.bitwidth) addr <<= self.mem_read_address1 + self.mem_read_address2 self.output1 <<= memory[addr] print(pyrtl.working_block()) with self.assertRaises(pyrtl.PyrtlError): pyrtl.working_block().sanity_check()
def test_memblock_to_memblock_direct_operation(self): temp = (self.memory[self.mem_read_address1] == self.memory[self.mem_read_address2]) temp = (self.memory[self.mem_read_address1] != self.memory[self.mem_read_address2]) temp = (self.memory[self.mem_read_address1] & self.memory[self.mem_read_address2]) temp = (self.memory[self.mem_read_address1] | self.memory[self.mem_read_address2]) temp = (self.memory[self.mem_read_address1] + self.memory[self.mem_read_address2]) temp = (self.memory[self.mem_read_address1] - self.memory[self.mem_read_address2]) temp2 = (self.memory[self.mem_read_address1] * self.memory[self.mem_read_address2]) self.output1 <<= temp self.output2 <<= temp2 pyrtl.working_block().sanity_check()
def test_net_odd_wires(self): wire = pyrtl.WireVector(2, 'wire') net = self.new_net(args=(wire, wire)) other_block = pyrtl.Block() wire._block = other_block self.invalid_net("net references different block", net) pyrtl.reset_working_block() wire = pyrtl.WireVector(2, 'wire') net = self.new_net(args=(wire,)) pyrtl.working_block().remove_wirevector(wire) self.invalid_net("net with unknown source", net)
def test_invalid_with_set_wb(self): x = pyrtl.Input() y = True pyrtl.set_working_block(self.block_a) with self.assertRaises(pyrtl.PyrtlError): with pyrtl.set_working_block(x): pass self.assertEqual(pyrtl.working_block(), self.block_a) with self.assertRaises(pyrtl.PyrtlError): with pyrtl.set_working_block(y): pass self.assertEqual(pyrtl.working_block(), self.block_a)
def test_multiple_elimination(self): ins = [pyrtl.Input(5) for i in range(3)] out_1 = pyrtl.Output(5) a = ins[0] ^ ins[1] b = ins[0] ^ ins[1] c = ins[0] ^ ins[1] out_1 <<= a | b | c pyrtl.common_subexp_elimination() self.num_net_of_type('^', 1) self.num_net_of_type('|', 2) pyrtl.working_block().sanity_check()
def test_different_arg_order(self): ins = [pyrtl.Input(5) for i in range(2)] outs = [pyrtl.Output(5) for i in range(2)] outs[0] <<= ins[1] & ins[0] outs[1] <<= ins[0] & ins[1] pyrtl.common_subexp_elimination() self.num_net_of_type('&', 1) self.num_net_of_type('w', 2) self.assert_num_net(3) self.assert_num_wires(5) pyrtl.working_block().sanity_check()
def test_concat(self): # concat's args are order dependent, therefore we need to check # that we aren't mangling them ins = [pyrtl.Input(5) for i in range(2)] outs = [pyrtl.Output(10) for i in range(2)] outs[0] <<= pyrtl.concat(ins[1], ins[0]) outs[1] <<= pyrtl.concat(ins[0], ins[1]) pyrtl.common_subexp_elimination() self.num_net_of_type('c', 2) self.num_net_of_type('w', 2) self.assert_num_net(4) self.assert_num_wires(6) pyrtl.working_block().sanity_check()
def test_order_dependent_ops(self): # subtract, lt, gt simarlarly are order dependent. # therefore we need to check that we aren't mangling them for op, opcode in ((operator.sub, '-'), (operator.gt, '>'), (operator.lt, '<')): pyrtl.reset_working_block() ins = [pyrtl.Input(5) for i in range(2)] outs = [pyrtl.Output(10) for i in range(2)] outs[0] <<= op(ins[1], ins[0]) outs[1] <<= op(ins[0], ins[1]) pyrtl.common_subexp_elimination() self.num_net_of_type(opcode, 2) self.num_net_of_type('w', 2) pyrtl.working_block().sanity_check()
def test_const_values_1(self): in_w = pyrtl.Input(5) out = pyrtl.Output(5) const = pyrtl.Const(23, 5) wire_1 = in_w + const wire_2 = in_w + const out <<= wire_1 | wire_2 pyrtl.common_subexp_elimination() self.num_net_of_type('+', 1) self.num_net_of_type('w', 1) self.assert_num_net(4) # because we cut off a bit after the add self.assert_num_wires(6) pyrtl.working_block().sanity_check()
def test_nested_elimination(self): ins = [pyrtl.Input(5) for i in range(3)] out_1 = pyrtl.Output(5) a = ins[0] ^ ins[0] b = ins[0] ^ ins[0] a2 = a & ins[2] b2 = b & ins[2] out_1 <<= a2 | b2 pyrtl.common_subexp_elimination() self.num_net_of_type('^', 1) self.num_net_of_type('&', 1) pyrtl.working_block().sanity_check()
def test_no_elimination_of_different_const_bitwidths(self): # trying to merge const wires with different bitwidths # together will cause mismatches in bitwidths of certain wires const_1 = pyrtl.Const(3, 3) const_2 = pyrtl.Const(3, 5) out_1 = pyrtl.Output(5) out_2 = pyrtl.Output(5) out_1 <<= const_1 | const_1 out_2 <<= const_2 | const_2 pyrtl.common_subexp_elimination() self.num_net_of_type('|', 2) self.num_net_of_type('w', 2) self.assert_num_net(6) self.assert_num_wires(9) pyrtl.working_block().sanity_check()
def check_graph_correctness(self, w_src_graph, w_dst_graph, has_virtual=False): for wire, net in w_src_graph.items(): if isinstance(wire, (pyrtl.Input, pyrtl.Const)): if has_virtual: self.assertIs(wire, net) else: self.fail("Input or Const, {} should not have a src".format(str(wire))) else: self.assertTrue(any(wire is w for w in net.dests)) for wire, nets in w_dst_graph.items(): if isinstance(wire, pyrtl.Output): if has_virtual: self.assertEqual(len(nets), 1) self.assertIs(wire, nets[0]) else: self.fail("Output, {} should not have a dst".format(str(wire))) else: for net in nets: self.assertTrue(any(wire is w for w in net.args)) self.assertEqual(len(nets), len(set(nets))) for net in pyrtl.working_block().logic: for wire in net.args: self.assertIn(net, w_dst_graph[wire]) for wire in net.dests: self.assertIs(w_src_graph[wire], net)
def circuit_equivalence(equv_func, in_wires=None, out_wire=None, block=None, print_invalid=True): """ Checks whether a circuit is equivalent to a python function :param equv_func: function to test circuit equivelence of. int args are passed in the order of the in_wires :param [Input] in_wires: wires for input (in order of args for equiv_func). default: all input wires, in their name's alphabetical order. :param Output out_wire: wire to use for output, default: find the only one :param Bool print_invalid: :return: bool """ block = pyrtl.working_block(block) in_wires = _get_inputs(in_wires, block) out_wire = _get_output(out_wire, block) # now we get into the algorithm bits_to_test = sum(w.bitwidth for w in in_wires) sim = pyrtl.Simulation() for test_val in range(2**bits_to_test): vals = _create_seq_list(in_wires, test_val) sim.step({w: v for w, v in zip(in_wires, vals)}) out_val = sim.inspect(out_wire) expected_val = equv_func(*vals) if not isinstance(expected_val, numbers.Integral): raise pyrtl.PyrtlError("Equv_func return %s, which is not an integer" % repr(expected_val)) if out_val != expected_val: if print_invalid: situation_str = ', '.join(str(w) + ' = ' + str(v) for w, v in zip(in_wires, vals)) print("in situation {}, got: {} expected: {}" .format(situation_str, out_val, expected_val)) return False return True
def color_based_on_op(net_attrs=None, block=None, attr_name='fill', net_colors=d3_category20_colors): net_color_dict = {op: color for op, color in zip(net_types, net_colors)} block = pyrtl.working_block(block) if net_attrs is None: net_attrs = {} for net in block.logic: add_attr(net_attrs, attr_name, net_color_dict[net.op], net) return net_attrs
def test_rename(self): block = pyrtl.working_block() w = pyrtl.WireVector(1, "test1") self.assertIn("test1", block.wirevector_by_name) self.assertIn(w, block.wirevector_set) w.name = "testJohn" self.assertNotIn("test1", block.wirevector_by_name) self.assertIn("testJohn", block.wirevector_by_name) self.assertIn(w, block.wirevector_set)
def everything_t_procedure(self, timing_val=None, opt_timing_val=None): # if there is a nondefault timing val supplied, then it will check # to make sure that the timing matches # this is a subprocess to do the synth and timing block = pyrtl.working_block() timing = estimate.TimingAnalysis(block) timing_max_length = timing.max_length() if timing_val is not None: self.assertEqual(timing_max_length, timing_val) critical_path = timing.critical_path() pyrtl.synthesize() pyrtl.optimize() block = pyrtl.working_block() timing = estimate.TimingAnalysis(block) timing_max_length = timing.max_length() if opt_timing_val is not None: self.assertEqual(timing_max_length, opt_timing_val) critical_path = timing.critical_path() pyrtl.and_inverter_synth() pyrtl.optimize() block = pyrtl.working_block() timing = estimate.TimingAnalysis(block) timing_max_length = timing.max_length() critical_path = timing.critical_path() block = pyrtl.working_block() self.num_net_of_type('|', 0, block) self.num_net_of_type('^', 0, block) pyrtl.nand_synth() pyrtl.optimize() block = pyrtl.working_block() timing = estimate.TimingAnalysis(block) timing_max_length = timing.max_length() critical_path = timing.critical_path() block.sanity_check() self.num_net_of_type('|', 0, block) self.num_net_of_type('^', 0, block) self.num_net_of_type('&', 0, block)
def test_basic_one_var_op_1(self): constwire = pyrtl.Const(0, 1) outwire = pyrtl.Output() outwire <<= ~constwire pyrtl.synthesize() pyrtl.optimize() block = pyrtl.working_block() self.num_net_of_type('~', 0, block) self.num_net_of_type('w', 1, block) self.assertEqual(len(block.logic), 1) self.assertEqual(len(block.wirevector_set), 2) self.num_wire_of_type(Const, 1, block)
def test_wirevector_1(self): inwire = pyrtl.Input(bitwidth=1) tempwire0, tempwire1 = pyrtl.WireVector(bitwidth=1), pyrtl.WireVector( bitwidth=1) tempwire2 = pyrtl.WireVector(bitwidth=1) outwire = pyrtl.Output() tempwire0 <<= inwire tempwire1 <<= tempwire0 tempwire2 <<= tempwire1 outwire <<= ~tempwire2 self.everything_t_procedure(1, 1) block = pyrtl.working_block() self.assert_num_net(3, block)
def test_wire_net_removal_2(self): inwire = pyrtl.Input(bitwidth=3) tempwire = pyrtl.WireVector() tempwire2 = pyrtl.WireVector() outwire = pyrtl.Output() tempwire <<= inwire tempwire2 <<= tempwire outwire <<= tempwire pyrtl.synthesize() pyrtl.optimize() # should remove the middle wires but keep the input block = pyrtl.working_block() self.assert_num_net(5, block) self.assert_num_wires(6, block)
def test_replace_output(self): def f(wire): w = pyrtl.clone_wire(wire, 'w2') return w, wire a, b = pyrtl.input_list('a/1 b/1') w1 = a & b o = pyrtl.Output(1, 'o') o <<= w1 src_nets, dst_nets = pyrtl.working_block().net_connections() self.assertEqual(dst_nets[w1], [pyrtl.LogicNet('w', None, (w1, ), (o, ))]) self.assertIn(o, src_nets) transform.wire_transform(f, select_types=pyrtl.Output, exclude_types=tuple()) w2 = pyrtl.working_block().get_wirevector_by_name('w2') src_nets, dst_nets = pyrtl.working_block().net_connections() self.assertEqual(dst_nets[w1], [pyrtl.LogicNet('w', None, (w1, ), (w2, ))]) self.assertNotIn(o, src_nets)
def test_const_folding_basic_two_var_op_2(self): inwire = pyrtl.Input(bitwidth=1) constwire = pyrtl.Const(0, 1) outwire = pyrtl.Output() outwire <<= inwire | constwire pyrtl.optimize() # should remove the and block and replace it with a # wire net (to separate the const from the output) block = pyrtl.working_block(None) self.assertEqual(self.num_net_of_type('|', block), 0) self.assertEqual(self.num_net_of_type('w', block), 1) self.assertEqual(len(block.logic), 1) self.assertEqual(len(block.wirevector_set), 2) self.assertEqual(self.num_wire_of_type(pyrtl.wire.Const, block), 0)
def test_block(self): a = pyrtl.Const(23) b = pyrtl.Input(5) o = pyrtl.Output(5) o <<= ~a & b old_block = pyrtl.working_block() old_block.sanity_check() self.assert_num_wires(5, old_block) self.assert_num_net(3, old_block) new_block = transform.copy_block() new_block.sanity_check() self.assert_num_wires(5, new_block) self.assert_num_net(3, old_block)
def test_basic_two_var_op_2(self): inwire = pyrtl.Input(bitwidth=1) constwire = pyrtl.Const(0, 1) outwire = pyrtl.Output() outwire <<= inwire | constwire pyrtl.optimize() # should remove the or block and replace it with a # wire net (to separate the const from the output) block = pyrtl.working_block(None) self.num_net_of_type('|', 0, block) self.num_net_of_type('w', 1, block) self.assert_num_net(1, block) self.assert_num_wires(2, block) self.num_wire_of_type(Const, 0, block)
def test_timing_error(self): inwire, inwire2 = pyrtl.Input(bitwidth=1), pyrtl.Input(bitwidth=1) tempwire, tempwire2 = pyrtl.WireVector(1), pyrtl.WireVector(1) outwire = pyrtl.Output() tempwire <<= ~(inwire & tempwire2) tempwire2 <<= ~(inwire2 & tempwire) outwire <<= tempwire with self.assertRaises(pyrtl.PyrtlError): pyrtl.synthesize() pyrtl.optimize() block = pyrtl.working_block() timing = estimate.TimingAnalysis(block) timing_max_length = timing.max_length()
def test_combo_blif_input_has_correct_io_interface(self): pyrtl.input_from_blif(full_adder_blif) x, y, cin, sumw, cout, bad = [ pyrtl.working_block().get_wirevector_by_name(s) for s in ['x', 'y', 'cin', 'sum', 'cout', 'bad'] ] self.assertIsNotNone(x) self.assertIsNotNone(y) self.assertIsNotNone(cin) self.assertIsNotNone(sumw) self.assertIsNotNone(cout) self.assertIsNone(bad) self.assertEquals(len(x), 1) self.assertEquals(len(y), 1) self.assertEquals(len(cin), 1) self.assertEquals(len(sumw), 1) self.assertEquals(len(cout), 1) io_input = pyrtl.working_block().wirevector_subset(pyrtl.Input) self.assertIn(x, io_input) self.assertIn(y, io_input) self.assertIn(cin, io_input) io_output = pyrtl.working_block().wirevector_subset(pyrtl.Output) self.assertIn(sumw, io_output) self.assertIn(cout, io_output)
def test_const_folding_basic_two_var_op_3(self): constwire = pyrtl.Const(0, 1) outwire = pyrtl.Output() # playing with edge cases outwire <<= constwire ^ constwire pyrtl.synthesize() pyrtl.optimize() # should remove the and block and replace it with a # wirevector (to separate the input from the output) block = pyrtl.working_block(None) self.assertEqual(self.num_net_of_type('|', block), 0) self.assertEqual(self.num_net_of_type('w', block), 1) self.assertEqual(len(block.logic), 1) self.assertEqual(len(block.wirevector_set), 2) self.assertEqual(self.num_wire_of_type(pyrtl.wire.Const, block), 1)
def test_basic_two_var_op_3(self): constwire = pyrtl.Const(0, 1) outwire = pyrtl.Output() # playing with edge cases outwire <<= constwire ^ constwire pyrtl.synthesize() pyrtl.optimize() # should remove the and block and replace it with a # wirevector (to separate the input from the output) block = pyrtl.working_block(None) self.num_net_of_type('^', 0, block) self.num_net_of_type('w', 1, block) self.assert_num_net(1, block) self.assert_num_wires(2, block) self.num_wire_of_type(Const, 1, block)
def test_as_graph_memory(self): m = pyrtl.MemBlock(addrwidth=2, bitwidth=2, name='m', max_read_ports=None) i = pyrtl.Register(bitwidth=2, name='i') o = pyrtl.WireVector(bitwidth=2, name='o') i.next <<= i + 1 m[i] <<= pyrtl.mux((m[i] != 0), 0, m[i]) o <<= m[i] b = pyrtl.working_block() src_g, dst_g = b.net_connections(False) self.check_graph_correctness(src_g, dst_g) src_g, dst_g = b.net_connections(True) self.check_graph_correctness(src_g, dst_g, True)
def test_replace_multiple_wires(self): j, n = pyrtl.Input(8), pyrtl.Output(8) o, h = pyrtl.WireVector(), pyrtl.WireVector() x, y = pyrtl.WireVector(8), pyrtl.WireVector(8) o <<= j h <<= o n <<= h block = pyrtl.working_block() src_nets, dst_nets = block.net_connections() transform.replace_wire_fast(o, x, x, src_nets, dst_nets) transform.replace_wire_fast(h, y, y, src_nets, dst_nets) for old_wire in (o, h): self.assertNotIn(old_wire, src_nets) self.assertNotIn(old_wire, dst_nets) self.assertNotIn(old_wire, block.wirevector_set) block.sanity_check()
def test_const_folding_adv_one_var_op_1(self): constwire = pyrtl.Const(0, 1) outwire = pyrtl.Output() tempwire = pyrtl.WireVector() reg = pyrtl.Register(1, 'test register') tempwire <<= ~constwire reg.next <<= tempwire outwire <<= reg pyrtl.synthesize() pyrtl.optimize() block = pyrtl.working_block(None) self.assertEqual(self.num_net_of_type('w', block), 1) self.assertEqual(len(block.logic), 1) self.assertEqual(len(block.wirevector_set), 2) self.assertEqual(self.num_wire_of_type(pyrtl.wire.Const, block), 1) self.assertEqual(self.num_wire_of_type(pyrtl.wire.Output, block), 1)
def test_adv_one_var_op_1(self): constwire = pyrtl.Const(0, 1) outwire = pyrtl.Output() tempwire = pyrtl.WireVector() reg = pyrtl.Register(1, 'test register') tempwire <<= ~constwire reg.next <<= tempwire outwire <<= reg pyrtl.synthesize() pyrtl.optimize() block = pyrtl.working_block(None) self.num_net_of_type('w', 1, block) self.assert_num_net(1, block) self.assert_num_wires(2, block) self.num_wire_of_type(Const, 1, block) self.num_wire_of_type(Output, 1, block)
def test_timing_error(self): inwire, inwire2 = pyrtl.Input(bitwidth=1), pyrtl.Input(bitwidth=1) tempwire, tempwire2 = pyrtl.WireVector(1), pyrtl.WireVector(1) outwire = pyrtl.Output() tempwire <<= ~(inwire & tempwire2) tempwire2 <<= ~(inwire2 & tempwire) outwire <<= tempwire output = six.StringIO() sys.stdout = output with self.assertRaises(pyrtl.PyrtlError): pyrtl.synthesize() pyrtl.optimize() block = pyrtl.working_block() _timing = pyrtl.TimingAnalysis(block) sys.stdout = sys.__stdout__ self.assertTrue(output.getvalue().startswith("Loop found:"))
def test_two_var_op_produce_not(self): constwire = pyrtl.Const(1, 1) inwire = pyrtl.Input(bitwidth=1) outwire = pyrtl.Output() # playing with edge cases outwire <<= constwire ^ inwire pyrtl.synthesize() pyrtl.optimize() # should remove the and block and replace it with a # wirevector (to separate the input from the output) block = pyrtl.working_block(None) self.num_net_of_type('~', 1, block) self.num_net_of_type('w', 1, block) self.num_net_of_type('s', 1, block) # due to synthesis self.assert_num_net(3, block) self.assert_num_wires(4, block) self.num_wire_of_type(Const, 0, block)
def test_wire_used_in_multiple_places(self): j, k = pyrtl.Input(8), pyrtl.Input(8) n, o = pyrtl.Output(8), pyrtl.Output(8) x = pyrtl.WireVector(8) r = j & k n <<= j | r o <<= r ^ k block = pyrtl.working_block() src_nets, dst_nets = block.net_connections() transform.replace_wire_fast(r, x, x, src_nets, dst_nets) for old_wire in (r, ): self.assertNotIn(old_wire, src_nets) self.assertNotIn(old_wire, dst_nets) self.assertNotIn(old_wire, block.wirevector_set) block.sanity_check()
def test_as_graph_duplicate_args(self): a = pyrtl.Input(3) x = pyrtl.Input(1) d = pyrtl.Output() b = a & a c = pyrtl.concat(a, a) m = pyrtl.MemBlock(addrwidth=3, bitwidth=3, name='m') m2 = pyrtl.MemBlock(addrwidth=1, bitwidth=1, name='m') d <<= m[a] m[a] <<= a m2[x] <<= pyrtl.MemBlock.EnabledWrite(x, x) b = pyrtl.working_block() src_g, dst_g = b.net_connections(False) self.check_graph_correctness(src_g, dst_g) src_g, dst_g = b.net_connections(True) self.check_graph_correctness(src_g, dst_g, True)
def test_step_with_internal_memory(self): def special_memory(read_addr, write_addr, data, wen): mem = pyrtl.MemBlock(bitwidth=32, addrwidth=5, name='special_mem') mem[write_addr] <<= pyrtl.MemBlock.EnabledWrite( data, wen & (write_addr > 0)) return mem[read_addr] read_addr = pyrtl.Input(5, 'read_addr') write_addr = pyrtl.Input(5, 'write_addr') data = pyrtl.Input(32, 'data') wen = pyrtl.Input(1, 'wen') res = pyrtl.Output(32, 'res') res <<= special_memory(read_addr, write_addr, data, wen) # Can only access it after the `special_memory` block has been instantiated/called special_mem = pyrtl.working_block().get_memblock_by_name('special_mem') sim = self.sim( memory_value_map={special_mem: { 0: 5, 1: 6, 2: 7, 3: 8, }}) inputs = { 'read_addr': '012012', 'write_addr': '012012', 'data': '890333', 'wen': '111000', } expected = { 'res': '567590', } # This should not fail sim.step_multiple(inputs, expected) # Let's check the memory contents too mem_map = sim.inspect_mem(special_mem) self.assertEqual(mem_map[0], 5) self.assertEqual(mem_map[1], 9) self.assertEqual(mem_map[2], 0) self.assertEqual(mem_map[3], 8)
def test_as_graph_2(self): a = pyrtl.Input(2) b = pyrtl.Input(2) c = pyrtl.Input(2) e = pyrtl.Output() f = pyrtl.Output() g = pyrtl.Output() d = a & c f <<= b & c e <<= d g <<= ~(d | b) b = pyrtl.working_block() src_g, dst_g = b.net_connections(False) self.check_graph_correctness(src_g, dst_g) src_g, dst_g = b.net_connections(True) self.check_graph_correctness(src_g, dst_g, True)
def test_two_var_op_correct_wire_prop(self): ins = [pyrtl.Input(1) for i in range(3)] outwire = pyrtl.Output() const_w = pyrtl.Const(0) temp1 = ins[1] & ins[2] temp2 = temp1 ^ const_w temp3 = const_w | temp2 outwire <<= temp3 & ins[2] pyrtl.optimize() block = pyrtl.working_block() block.sanity_check() # just in case self.num_net_of_type('&', 2) self.num_net_of_type('w', 1) self.assert_num_net(3) self.assert_num_wires(6) self.num_wire_of_type(Const, 0)
def test_one_bit_selects(self): a = pyrtl.Const(0b101101001101) b = pyrtl.Output(6, 'b') b <<= a[::2] # bits 0, 2, 4, 6, 8, and 10 of wire a block = pyrtl.working_block() select_nets = list(block.logic_subset(op='s')) self.assertEqual(len(select_nets), 1) self.assertEqual(tuple(select_nets[0].op_param), (0, 2, 4, 6, 8, 10)) pyrtl.one_bit_selects() select_nets = list(block.logic_subset(op='s')) for net in select_nets: indices = net.op_param self.assertEqual(len(indices), 1) sim = pyrtl.Simulation() sim.step({}) self.assertEqual(sim.inspect('b'), 0b00011011)
def circuit_equivalence(equv_func, in_wires=None, out_wire=None, block=None, print_invalid=True): """ Checks whether a circuit is equivalent to a python function :param equv_func: function to test circuit equivelence of. int args are passed in the order of the in_wires :param [Input] in_wires: wires for input (in order of args for equiv_func). default: all input wires, in their name's alphabetical order. :param Output out_wire: wire to use for output, default: find the only one :param Bool print_invalid: :return: bool """ block = pyrtl.working_block(block) in_wires = _get_inputs(in_wires, block) out_wire = _get_output(out_wire, block) # now we get into the algorithm bits_to_test = sum(w.bitwidth for w in in_wires) sim = pyrtl.Simulation() for test_val in range(2**bits_to_test): vals = _create_seq_list(in_wires, test_val) sim.step({w: v for w, v in zip(in_wires, vals)}) out_val = sim.inspect(out_wire) expected_val = equv_func(*vals) if not isinstance(expected_val, numbers.Integral): raise pyrtl.PyrtlError( "Equv_func return %s, which is not an integer" % repr(expected_val)) if out_val != expected_val: if print_invalid: situation_str = ', '.join( str(w) + ' = ' + str(v) for w, v in zip(in_wires, vals)) print("in situation {}, got: {} expected: {}".format( situation_str, out_val, expected_val)) return False return True
def test_two_var_op_correct_not_wire_replacement(self): ins = [pyrtl.Input(1) for i in range(3)] outwire = pyrtl.Output() const_0 = pyrtl.Const(0) const_1 = pyrtl.Const(1) temp1 = ins[0] & ins[1] temp2 = const_0 | temp1 temp3 = temp2 ^ const_1 outwire <<= temp3 & ins[2] pyrtl.optimize() block = pyrtl.working_block() block.sanity_check() # just in case self.num_net_of_type('&', 2) self.num_net_of_type('~', 1) self.num_net_of_type('w', 1) self.assert_num_net(4) self.assert_num_wires(7) self.num_wire_of_type(Const, 0)
def test_block_iterators(self): # testing to see that it properly runs a trivial case inwire = pyrtl.Input(bitwidth=1, name="inwire1") inwire2 = pyrtl.Input(bitwidth=1) inwire3 = pyrtl.Input(bitwidth=1) tempwire = pyrtl.WireVector() tempwire2 = pyrtl.WireVector() outwire = pyrtl.Output() tempwire <<= inwire | inwire2 tempwire2 <<= ~tempwire outwire <<= tempwire2 & inwire3 block = pyrtl.working_block() i = 0 for net in block: self.assertFalse(i > 100, "Too many iterations happened") i += 1 print(str(net)) for net in block.logic: print(net)
def test_copy_mem(self): ins = [pyrtl.Input(5) for i in range(4)] out = pyrtl.Output(5) mem1 = pyrtl.MemBlock(5, 5) mem2 = pyrtl.MemBlock(5, 5) mem1_o1 = mem1[ins[0]] mem1[ins[1]] <<= ins[2] mem2_o2 = mem2[ins[3]] out <<= mem1_o1 & mem2_o2 old_block = pyrtl.working_block() old_block.sanity_check() self.num_net_of_type('m', 2, old_block) self.num_net_of_type('@', 1, old_block) self.num_net_of_type('&', 1, old_block) self.num_memories(2, old_block) new_block = transform.copy_block() self.num_net_of_type('m', 2, new_block) self.num_net_of_type('@', 1, new_block) self.num_net_of_type('&', 1, new_block) self.num_memories(2, new_block)
def test_adv_one_var_op_2(self): # this one tests to see that an input wirevector is properly preserved inwire = pyrtl.Input(bitwidth=1) outwire = pyrtl.Output() tempwire = pyrtl.WireVector() reg = pyrtl.Register(1, 'test register') tempwire <<= ~inwire reg.next <<= tempwire outwire <<= reg pyrtl.synthesize() pyrtl.optimize() # should remove the and block and replace it with a # wire net (to separate the input from the output) block = pyrtl.working_block(None) # Note: the current implementation still sticks a wire net between # a register 'nextsetter' wire and the output wire self.num_net_of_type('w', 1, block) self.assert_num_net(4, block) self.assert_num_wires(5, block) self.num_wire_of_type(Const, 0, block) self.num_wire_of_type(Output, 1, block)
def test_as_graph_trivial(self): i = pyrtl.Input(1) o = pyrtl.Output(1) b = pyrtl.working_block() net = pyrtl.LogicNet('~', None, (i,), (o,)) b.add_net(net) src_g, dst_g = b.net_connections(False) self.check_graph_correctness(src_g, dst_g) self.assertEqual(src_g[o], net) self.assertEqual(dst_g[i][0], net) self.assertEqual(len(dst_g[i]), 1) self.assertNotIn(i, src_g) self.assertNotIn(o, dst_g) src_g, dst_g = b.net_connections(True) self.check_graph_correctness(src_g, dst_g, True) self.assertEqual(src_g[o], net) self.assertEqual(dst_g[i][0], net) self.assertEqual(len(dst_g[i]), 1) self.assertIs(src_g[i], i) self.assertIs(dst_g[o][0], o) self.assertEqual(len(dst_g[o]), 1)
1- 1 -1 1 .names cin ind2 $and$FA.v:19$12_Y 11 1 .names $and$FA.v:19$11_Y $and$FA.v:19$12_Y cout 1- 1 -1 1 .names $not$FA.v:11$1_Y y ind0 11 1 .end """ pyrtl.input_from_blif(full_adder_blif) # Have to find the actual wire vectors generated from the names in the blif file x, y, cin = [ pyrtl.working_block().get_wirevector_by_name(s) for s in ['x', 'y', 'cin'] ] io_vectors = pyrtl.working_block().wirevector_subset( (pyrtl.Input, pyrtl.Output)) # We are only going to trace the input and output vectors for clarity sim_trace = pyrtl.SimulationTrace(wires_to_track=io_vectors) # Now simulate the logic with some random inputs sim = pyrtl.Simulation(tracer=sim_trace) for i in range(15): # here we actually generate random booleans for the inputs sim.step({ 'x': random.choice([0, 1]), 'y': random.choice([0, 1]), 'cin': random.choice([0, 1]) })