async def unary(din: Uint['w_data']) -> Uint['2**(int(w_data)-1)']: '''Returns the unary representation of a binary number''' async with din as val: if val > 2**(din.dtype.width - 1): sim_log().error( f'{val} supplied, but only numbers <= {2**(din.dtype.width-1)} supported for this instance' ) if val == 0: yield 0 else: yield int('1' * int(val), 2)
def read(self): self.active = self.c_get_api(self.dout) # print( # f'{self.port.basename}: {self.active}, {self.from_c_data(self.dout)}' # ) if self.active: try: return self.port.dtype.decode(self.from_c_data(self.dout)) except ValueError as e: sim_log().error( str(e) + f'\n - received at port "{self.port.name}"') else: raise CosimNoData
def before_run(self, sim): self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) if self.run_cosim: import uuid filename = str(uuid.uuid4()) else: filename = "svsock.s" self.port = os.path.join(tempfile.gettempdir(), filename) if os.path.exists(self.port): os.remove(self.port) self.sock.bind(self.port) # Listen for incoming connections # self.sock.listen(len(self.gear.in_ports) + len(self.gear.out_ports)) self.sock.listen(1) self.build() # if self.rebuild: # self.build() # else: # self.kwds['nobuild'] = True if not self.run_cosim: self.invoke_cosim() self.conn, addr = self.sock.accept() else: self.sock.settimeout(5) self.cosim_pid = self.invoke_cosim() ret = None while ret is None: try: self.conn, addr = self.sock.accept() break except socket.timeout: ret = self.cosim_pid.poll() if ret is not None: sim_log().error( f'Cosimulator error: {ret}. Check log File "{self.outdir}/log.log"' ) raise CosimulatorStartError msg = self.conn.recv(1024) port_name = msg.decode() sim_log().debug(f"Connection received for {port_name}")
def typeseq(t, v): if type(v) == t: yield v else: try: for d in TypeDrvVisitor().visit(v, t): try: yield t(d) except (TypeError, ValueError): sim_log().error( f'Cannot convert value "{d}" to type "{repr(t)}"') except (TypeError, ValueError): sim_log().error( f'Cannot convert sequence "{v}" to the "{repr(t)}"')
def find_target_cons(intf): # Who is consumer port? Case when not broadcast! # cons_rtl_port = intf.consumers[0] end_c = get_end_consumer(intf) if len(end_c) != 1: if len(end_c) > 1: sim_log().debug(f'Find target cons: found broadcast') return None cons_rtl_port = end_c[0] cons_rtl_node, port_id = cons_rtl_port.node, cons_rtl_port.index cons_gear = cons_rtl_node.gear cons_port = cons_gear.in_ports[port_id] return cons_port
def get_rand(self, name): ret = os.system( f"cd {self.outdir}; g++ -fpic -shared -I. -I$SYSTEMC_INCLUDE -I$SCV_INCLUDE -Wall -Wformat -O2 $SCV_LIBDIR/libscv.so -L$SYSTEMC_LIBRID $SYSTEMC_LIBDIR/libsystemc.so -lpthread -pthread -Wl,-rpath -Wl,$SCV_LIBDIR -Wl,-rpath -Wl,$SYSTEMC_LIBDIR -o {name} {name}.cpp" ) if ret != 0: sim_log().warning( 'Possible reason for exception: Queues not supported in SCV') raise SCVCompileError( f'Constrained random library compilation failed for module {name}.' ) scvlib = ctypes.CDLL(os.path.join(self.outdir, name)) t = self.get_dtype_by_name(name) return SCVTypeSeqVisitor(scvlib).visit(t, name)
async def scoreboard(*din: b't', report=None, cmp=None) -> None: """Generic scoreboard used from comparing actual results from the DUT to expected results. Eventual mismatches are asserted using the ``sim_assert`` function meaning that any ``error`` behaviour is controled via the ``sim`` logger ``error`` settings. Args: din: Outputs from both the DUT and ref. model. All intpus are a PyGears interface report: List to with comparison results are appended tolerance: Optional tolerance when comparing results. The DUT result must be in the (expected - tolerance, expected+tolerance) range Returns: None """ def match_exact(x, y): return x == y if cmp is None: cmp = match_exact # print(f'Number of matches: -\r', end='') cnt = 0 match_cnt = 0 try: while True: items = [] for d in din: items.append(await d.get()) match = all(cmp(v, items[0]) for v in items) if report is not None: report.append({'match': match, 'items': items}) cnt += 1 if match: match_cnt += 1 sim_assert(match, f'mismatch on #{cnt}: {items[0]}, {items[1]}') # print(f'Number of matches: {match_cnt:>4}/{cnt:>4}\r', end='') except GearDone as e: sim_log().info(f'Number of matches: {match_cnt:>4}/{cnt:>4}') raise e
def find_target_prod(intf): # Who is producer gear? # prod_rtl_port = intf.producer end_p = get_producer(intf) if len(end_p) != 1: return None if isinstance(end_p[0], OutPort): prod_rtl_port = end_p[0] prod_rtl_node = prod_rtl_port.node prod_gear = prod_rtl_node.gear else: prod_gear = end_p[0].gear if len(prod_gear.child): if len(prod_gear.child) > 1: sim_log().warning( f'ActivityCosim: prod has more than one child. Setting on first.' ) return prod_gear.child[0] else: return prod_gear
def finish(self): if self.sock: if self.conn: try: self.send_cmd(CMD_FINISH) time.sleep(0.5) except BrokenPipeError: pass sim_log().info(f'Done. Closing the socket...') self.sock.close() time.sleep(1) if self.cosim_pid is not None: self.cosim_pid.terminate() self.sock = None self.cosim_pid = None self.conn = None atexit.unregister(self.finish)
def after_run(self, sim): for sim_gear in sim.sim_gears: module = sim_gear.gear if module.definition == decouple_din: if not module.queue.empty(): if 'data_in_decouple' in self.hooks: self.hooks['data_in_decouple'](module) sim_log().error(f'Data left in decouple: {module.name}') for p in module.in_ports: status = self.get_port_status(p) if status == "active": src_port = get_source_producer(p, sim=True).consumers[0] if src_port.gear.definition == const: # Skip constants since they are never done continue if 'not_ack' in self.hooks: self.hooks['not_ack'](module, p) sim_log().error( f'{src_port.gear.name}.{src_port.basename} -> {module.name}.{p.basename} was not acknowledged' ) if status == "waited": src_port = self.blockers[p] if 'waiting' in self.hooks: self.hooks['waiting'](module, p) sim_log().debug( f'{p.gear.name}.{p.basename} waiting on {src_port.gear.name}.{src_port.basename}' )
def __init__(self, trace_fn='pygears.vcd', include=Inject('debug/trace'), tlm=False, shmidcat=Inject('sim_extens/vcd/shmidcat'), vcd_fifo=Inject('sim_extens/vcd/vcd_fifo'), sim=Inject('sim/simulator'), outdir=Inject('results-dir')): super().__init__() self.sim = sim self.finished = False self.vcd_fifo = vcd_fifo self.shmidcat = shmidcat self.outdir = outdir self.trace_fn = None self.shmid_proc = None vcd_visitor = VCDHierVisitor(include, tlm) vcd_visitor.visit(find('/')) if not vcd_visitor.vcd_vars: self.deactivate() return self.trace_fn = os.path.abspath(os.path.join(self.outdir, trace_fn)) atexit.register(self.finish) try: subprocess.call(f"rm -f {self.trace_fn}", shell=True) except OSError: pass if self.vcd_fifo: subprocess.call(f"mkfifo {self.trace_fn}", shell=True) else: sim_log().info(f'Main VCD dump to "{self.trace_fn}"') if self.shmidcat: self.shmid_proc = subprocess.Popen(f'shmidcat {self.trace_fn}', shell=True, stdout=subprocess.PIPE) # Wait for shmidcat to actually open the pipe, which is necessary # to happen prior to init of the verilator. If shmidcat does not # open the pipe, verilator will get stuck import time time.sleep(0.1) self.vcd_file = open(self.trace_fn, 'w') if self.shmidcat: self.shmid = self.shmid_proc.stdout.readline().decode().strip() sim_log().info(f'Main VCD dump to shared memory at 0x{self.shmid}') self.writer = VCDWriter(self.vcd_file, timescale='1 ns', date='today') reg['VCDWriter'] = self.writer reg['VCD'] = self self.clk_var = self.writer.register_var('', 'clk', 'wire', size=1, init=1) self.timestep_var = self.writer.register_var('', 'timestep', 'integer', init=0) self.handhake = set() self.vcd_vars = { intf: register_traces_for_intf(intf.dtype, scope, self.writer) for intf, scope in vcd_visitor.vcd_vars.items() } for intf in self.vcd_vars: intf.events['put'].append(self.intf_put) intf.events['ack'].append(self.intf_ack) self.writer.flush()
def get_rand(self, name): sim_log().error('Get rand function not implemented.')
def create_type_cons(self, desc={}): sim_log().error('Create type constraints function not implemented.')
def after_call_forward(self, sim, sim_gear): sim_log().info(f'forward') return True
def after_call_back(self, sim, sim_gear): sim_log().info(f'back') return True
async def register_file_write(request: TWriteRequest, *, storage): async with request as req: if req['addr'] != 0: sim_log().info(f'Writing {req["data"]} to x{int(req["addr"])}') storage[int(req['addr'])] = req['data']
def cosim_activity(self, g, top_name): outdir = reg['results-dir'] activity_path = os.path.join(outdir, 'activity.log') if not os.path.isfile(activity_path): return with open(activity_path, 'r') as log: for line in log: activity_name = line.rpartition(': ')[0] activity_name = activity_name.replace('top.dut.', f'{top_name}/') activity_name = activity_name.rpartition('.')[0] activity_name = activity_name.replace('_i.', '/') gear_name, _, intf_name = activity_name.rpartition('/') # Const always has valid high const_regex = r'.*_const(?P<num>\d+)_s' const_regex_one = r'.*_const_s' if not (re.match(const_regex, intf_name) or re.match(const_regex_one, intf_name)): sim_log().error( f'Cosim spy not acknowledged: {activity_name}') if self.draw_graph: bc_regex = r'.*_bc_(?P<num>\d+).*' if re.match(bc_regex, intf_name): sim_log().debug( f'Activity monitor cosim: bc not supported {activity_name}' ) continue intf = find_target_intf(gear_name, intf_name) if intf is None: sim_log().error( f'Cannot find matching interface for {activity_name}' ) continue if intf.is_broadcast: sim_log().debug( f'Intf bc not supported {activity_name}') continue try: prod_gear = find_target_prod(intf) set_blocking_node(g, prod_gear) except (KeyError, AttributeError): sim_log().debug( f'Cannot find node for {activity_name}') try: cons_port = find_target_cons(intf) set_blocking_edge(g, cons_port) except (KeyError, AttributeError): sim_log().debug( f'Cannot find edge for {activity_name}')
def setup(self): # TODO: When reusing existing verilated build, add test to check # whether verilated module is the same as the current one (Maybe hash check?) if self.rebuild: sim_log().info(f'Verilating...') build(self.top, self.outdir, postsynth=False, lang=self.lang) sim_log().info(f'Done') file_struct = get_file_struct(self.top, self.outdir) tracing_enabled = bool(reg['debug/trace']) if tracing_enabled: sim_log().info(f"Debug: {reg['debug/trace']}") self.trace_fn = os.path.join(reg["results-dir"], f'{self.name}.vcd') try: subprocess.call(f"rm -f {self.trace_fn}", shell=True) except OSError: pass if self.vcd_fifo: subprocess.call(f"mkfifo {self.trace_fn}", shell=True) else: sim_log().info(f'Verilator VCD dump to "{self.trace_fn}"') else: self.trace_fn = '' try: self.verilib = ctypes.CDLL(file_struct['dll_path']) except OSError: raise VerilatorCompileError( f'Verilator compiled library for the gear "{self.gear.name}"' f' not found at: "{file_struct["dll_path"]}"') self.finished = False atexit.register(self._finish) if self.shmidcat and tracing_enabled: self.shmid_proc = subprocess.Popen(f'shmidcat {self.trace_fn}', shell=True, stdout=subprocess.PIPE) # Wait for shmidcat to actually open the pipe, which is necessary # to happen prior to init of the verilator. If shmidcat does not # open the pipe, verilator will get stuck import time time.sleep(0.1) self.verilib.init.argtypes = [ctypes.c_char_p] assert self.verilib.init(self.trace_fn.encode('utf8')) != 0 if self.shmid_proc: self.shmid = self.shmid_proc.stdout.readline().decode().strip() sim_log().info( f'Verilator VCD dump to shared memory at 0x{self.shmid}') self.handlers = {} for cp in self.in_cosim_ports: self.handlers[cp.name] = CInputDrv(self.verilib, cp.port, cp.name) for cp in self.out_cosim_ports: self.handlers[cp.name] = COutputDrv(self.verilib, cp.port, cp.name) super().setup()