def test_time_est_unchanged(self): a = pyrtl.Const(2, 8) b = pyrtl.Const(85, 8) zero = pyrtl.Const(0, 1) reg = pyrtl.Register(8) mem = pyrtl.MemBlock(8, 8) out = pyrtl.Output(8) nota, aLSB, athenb, aORb, aANDb, aNANDb, \ aXORb, aequalsb, altb, agtb, aselectb, \ aplusb, bminusa, atimesb, memread = [pyrtl.Output() for i in range(15)] out <<= zero nota <<= ~a aLSB <<= a[0] athenb <<= pyrtl.concat(a, b) aORb <<= a | b aANDb <<= a & b aNANDb <<= a.nand(b) aXORb <<= a ^ b aequalsb <<= a == b altb <<= a < b agtb <<= a > b aselectb <<= pyrtl.select(zero, a, b) reg.next <<= a aplusb <<= a + b bminusa <<= a - b atimesb <<= a * b memread <<= mem[0] mem[1] <<= a timing = estimate.TimingAnalysis() self.assertEqual(timing.max_freq(), 610.2770657878676) self.assertEquals(timing.max_length(), 1255.6000000000001)
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_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 add_timing_info(net_graph=None, net_attrs=None, edge_attr=None, timing=None, scale=.4, offset=50): net_graph, net_attrs, edge_attr = _check_graph_items( net_graph, net_attrs, edge_attr) if timing is None: from pyrtl.analysis import estimate timing = estimate.TimingAnalysis() wire_src, wire_dst = pyrtl.working_block().net_connections( include_virtual_nodes=True) tmap = timing.timing_map lDist = 'linkDistance' for wire, delay in tmap.items(): item_offset = offset if isinstance(wire_src, (pyrtl.Input, pyrtl.Const, pyrtl.Register)): item_offset -= 40 add_attr(net_attrs, 'depth', delay * scale + item_offset, wire_src[wire]) block = pyrtl.working_block() # deal with special cases for element in block.wirevector_subset(pyrtl.Output): add_attr(net_attrs, 'depth', tmap[element] * scale + offset + 20, element) # add_attr(edge_attr, lDist, 30 + 20, element, element) # add custom links for element in block.logic_subset('@r'): max_timing = max(*(tmap[w] for w in element.args)) add_attr(net_attrs, 'depth', max_timing * scale + offset + 20, element) # now figure out the edges: for src_net, sn_dict in net_graph.items(): for dst_net, dn_wire in sn_dict.items(): depth_dist = net_attrs[dst_net]['depth'] - net_attrs[src_net][ 'depth'] dist = math.sqrt(link_min_dist**2 + (depth_dist * 1.1)**2) add_attr(edge_attr, lDist, dist, src_net, dst_net) return net_attrs, edge_attr
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 = estimate.TimingAnalysis(block) sys.stdout = sys.__stdout__ self.assertTrue(output.getvalue().startswith("Loop found:"))
# Timing and area usage are key considerations of any hardware block that one # makes. PyRTL provides functions to do these operations. # Creating a sample hardware block pyrtl.reset_working_block() const_wire = pyrtl.Const(6, bitwidth=4) in_wire2 = pyrtl.Input(bitwidth=4, name="input2") out_wire = pyrtl.Output(bitwidth=5, name="output") out_wire <<= const_wire + in_wire2 # Now we will do the timing analysis as well as print out the critical path # Generating timing analysis information print("Pre Synthesis:") timing = estimate.TimingAnalysis() timing.print_max_length() # We are also able to print out the critical paths as well as get them # back as an array. critical_path_info = timing.critical_path() # --- Part 2: Area Analysis -------------------------------------------------- # PyRTL also provides estimates for the area that would be used up if the # circuit was printed as an ASIC. logic_area, mem_area = estimate.area_estimation(tech_in_nm=65) est_area = logic_area + mem_area print("Estimated Area of block", est_area, "sq mm") print()