def test_fir_random_type(impl, seed, do_cosim): # Set random seed set_seed(seed) log.info(f'{__name__} impl: {impl}, seed: {seed}') fixp_w = random.randint(16, 32) int_w = random.randint(1, 3) t_b = Fixp[int_w, fixp_w] log.info( f'{__name__} FIR input type t_b: {t_b} min: {t_b.fmin}, max: {t_b.fmax}' ) seq = [] # generate multiple constant sequences of certain size for i in range(10): num = np.random.uniform(t_b.fmin, t_b.fmax) for i in range(50): seq.append(num) # add a random sequence of certain size seq.extend(random_seq(t_b, 100)) # genrate random numbers in [-1,1) # seq = np.random.random(size=(100, )) * 2 - 1 log.debug(f'Generated sequence: {seq}') res = fir_sim(impl, t_b, seq, do_cosim=do_cosim)
def test_iir_random(impl, seed, do_cosim): log.info(f'Running test_iir_random seed: {seed}') set_seed(seed) ftype = Fixp[5, 32] seq = constant_seq(ftype, 10, 0) seq.extend(random_seq(ftype, 100)) seq.extend(constant_seq(ftype, 10, 0)) iir_sim(impl, ftype, ftype, ftype, seq, do_cosim=do_cosim)
def test_fir_random(impl, seed, do_cosim): # Set random seed set_seed(seed) log.info(f'Running {__name__} impl: {impl}, seed: {seed}') t_b = Fixp[1, 15] # genrate random numbers in [-1,1) seq = np.random.random(size=(100, )) * 2 - 1 log.debug(f'Generated sequence: {seq}') res = fir_sim(impl, t_b, seq, do_cosim=do_cosim)
def xsim(outdir=None, makefile=True, files=None, includes=None, batch=True, seed=None): outdir = os.path.abspath(outdir) if not makefile and not shutil.which('xsim'): raise CosimulatorUnavailable dpi_path = os.path.abspath(os.path.join(ROOT_DIR, 'sim', 'dpi')) context = { 'dti_verif_path': dpi_path, 'outdir': outdir, 'top_name': '_top', 'files': files, 'includes': includes, } base_addr = os.path.dirname(__file__) env = jinja2.Environment(loader=jinja2.FileSystemLoader(base_addr), trim_blocks=True, lstrip_blocks=True) res = env.get_template('run_xsim.j2').render(context) fname = save_file('run_xsim.sh', outdir, res) os.chmod(fname, 0o777) kwds = { 'batch': batch, 'seed': seed if seed is not None else reg["sim/rand_seed"] } if makefile: log.info(f"Waiting for manual XSim invocation. Run script: {fname}...") return None args = ' '.join(f'-{k} {v if not isinstance(v, bool) else ""}' for k, v in kwds.items() if not isinstance(v, bool) or v) # stdout = None stdout = DEVNULL log.info(f'Starting XSim...') return Popen([f'./run_xsim.sh'] + args.split(' '), stdout=stdout, stderr=stdout, cwd=outdir)
def test_iir_limits(fixp_w, int_w, impl, seed, do_cosim): """[Drive filter with extreme values [min, 0 , max] """ log.info(f'Running test_iir_limits, seed: {seed}') set_seed(seed) factor = 0.5 # supported factor ftype = Fixp[int_w, fixp_w] print(f'max possible value {ftype.fmax}') extremes = [[0 for i in range(50)]] extremes.append([ftype.fmin * factor for i in range(10)]) seq = random_choice_seq(extremes, 10) extremes.append([ftype.fmax * factor for i in range(10)]) seq = random_choice_seq(extremes, 10) iir_sim(impl, ftype, ftype, ftype, seq, do_cosim=do_cosim)
def test_iir_direct(tmpdir, impl, seed, do_cosim): reg['sim/rand_seed'] = seed random.seed(reg['sim/rand_seed']) log.info( f'Running test_fir_direct tmpdir: {tmpdir}, impl: {impl}, seed: {seed}' ) reg['sim/clk_freq'] = 100000 t = list(range(reg['sim/clk_freq']))[0:100] fs = reg['sim/clk_freq'] f1 = 1000 f2 = 70000 seq = [] for n in t: seq.append(1 * sin(2 * pi * f1 / fs * n) + 0.1 * sin(2 * pi * f2 / fs * n)) sos = signal.butter(N=5, Wn=30000 / 100000, btype='lowpass', analog=False, output='sos') a, b = [], [] for s in sos: b.append(list(s[0:3])) a.append(list(s[3:])) t_coef = Fixp[5, 32] b = [[t_coef(coef) for coef in section] for section in b] a = [[t_coef(coef) for coef in section] for section in a] gain = [Fixp[2, 23](1)] * len(b) ref = signal.sosfilt(sos, seq) fp_ref = [float(r) for r in ref] log.debug(f'Generated sequence: {seq}') drv(t=Fixp[5, 24], seq=seq) \ | impl(a=a, b=b, gain=gain, ogain=Fixp[5, 24](1)) \ | Float \ | check(ref=fp_ref[:len(seq)], cmp=lambda x, y: abs(x - y) < 1e-3) if do_cosim: cosim(f'{impl}', 'verilator', outdir=tmpdir, timeout=1000) sim(tmpdir, check_activity=False)
def sim(resdir=None, timeout=None, extens=None, run=True, check_activity=False, seed=None): if reg['sim/dryrun']: return if extens is None: extens = [] extens.extend(reg['sim/extens']) if resdir is None: resdir = reg['results-dir'] reg['results-dir'] = resdir os.makedirs(resdir, exist_ok=True) if reg['sim/rand_seed'] is None: if seed is None: seed = random.randrange(sys.maxsize) reg['sim/rand_seed'] = seed random.seed(reg['sim/rand_seed']) log.info(f'Running sim with seed: {reg["sim/rand_seed"]}') loop = EventLoop() asyncio.set_event_loop(loop) reg['sim/simulator'] = loop if check_activity: from pygears.sim.extens.activity import ActivityChecker if ActivityChecker not in extens: extens.append(ActivityChecker) for oper in itertools.chain(reg['sim/flow'], extens): oper() if run: loop.run(timeout) return loop
def test_iir_random_type(impl, seed, do_cosim): log.info(f'Running test_iir_random, seed: {seed}') set_seed(seed) # minimum supported precision Fixp[3,19] int_w = random.randint(3, 7) fixp_w = random.randint(int_w + 19, int_w + 32) ftype = Fixp[int_w, fixp_w] log.info( f'{__name__} FIR input type t_b: {ftype} min: {ftype.fmin}, max: {ftype.fmax}' ) seq = constant_seq(ftype, 10, 0) seq.extend(random_seq(ftype, 100)) seq.extend(constant_seq(ftype, 10, 0)) iir_sim(impl, ftype, ftype, ftype, seq, do_cosim=do_cosim)
def finish(self): if self.sock: if self.conn: try: self.send_cmd(CMD_FINISH) time.sleep(0.5) except BrokenPipeError: pass 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 test_fir_sine(freq, impl, seed, do_cosim): """[Drive filter with sine signal at fs fs/2 and fs*2 """ # Set random seed set_seed(seed) # set clock freq reg['sim/clk_freq'] = freq t = list(range(reg['sim/clk_freq']))[0:100] fs = reg['sim/clk_freq'] f1 = freq / 100 log.info(f'Running {__name__} impl: {impl}, seed: {seed}, fs:{fs},f1:{f1}') ftype = Fixp[5, 32] seq = [0 for i in range(10)] seq.extend(sine_seq(f1, fs, 200, ftype)) seq.extend([0 for i in range(100)]) seq.extend(sine_seq(f1, fs / 2, 100, ftype)) seq.extend([0 for i in range(100)]) seq.extend(sine_seq(f1, fs * 2, 400, ftype)) seq.extend([0 for i in range(10)]) res = iir_sim(impl, ftype, ftype, ftype, seq, do_cosim=do_cosim)
def test_fir_limits(fixp_w, int_w, impl, seed, do_cosim): """[Drive filter with extreme values [min, 0 , max] """ # Set random seed set_seed(seed) log.info(f'Running {__name__} impl: {impl}, seed: {seed}') t_b = Fixp[int_w, fixp_w] log.info( f'{__name__} FIR input type t_b: {t_b} min: {t_b.fmin}, max: {t_b.fmax}' ) extremes = [[0 for i in range(50)]] extremes.append([t_b.fmin for i in range(50)]) extremes.append([t_b.fmax for i in range(50)]) seq = random_choice_seq(extremes, 10) log.debug(f'Generated sequence: {seq}') res = fir_sim(impl, t_b, seq, do_cosim=do_cosim)
def test_fir_sine(freq, impl, seed, do_cosim): """[Drive filter with sine signal at fs fs/2 and fs*2 """ # Set random seed set_seed(seed) # set clock freq reg['sim/clk_freq'] = freq t = list(range(reg['sim/clk_freq']))[0:100] fs = reg['sim/clk_freq'] f1 = freq / 100 log.info(f'Running {__name__} impl: {impl}, seed: {seed}') t_b = Fixp[1, 15] seq = [0 for i in range(10)] seq.extend(sine_seq(f1, fs, 200, t_b)) seq.extend(sine_seq(f1, fs / 2, 100, t_b)) seq.extend(sine_seq(f1, fs * 2, 400, t_b)) seq.extend([0 for i in range(10)]) log.debug(f'Generated sequence: {seq}') res = fir_sim(impl, t_b, seq, do_cosim=do_cosim)
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: 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() 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 = { p: register_traces_for_intf(p.dtype, scope, self.writer) for p, scope in vcd_visitor.vcd_vars.items() } self.writer.flush()
def after_call_forward(self, sim, sim_gear): log.info(f'forward') return True
def sim_loop(self, timeout): clk = reg['sim/clk_event'] delta = reg['sim/delta_event'] global gear_reg, sim_reg gear_reg = reg['gear']._dict sim_reg = reg['sim']._dict reg['sim/timestep'] = 0 timestep = -1 start_time = time.time() finished = False log.info("-------------- Simulation start --------------") while (self.forward_ready or self.back_ready or self._schedule_to_finish or not finished): # Conditional timeout context with contextlib.ExitStack() as stack: if self.step_timeout: stack.enter_context(stopit.ThreadingTimeout(self.step_timeout, swallow_exc=False)) finished = not bool(self.forward_ready or self.back_ready or self._schedule_to_finish) timestep += 1 reg['sim/timestep'] = timestep if (timeout is not None) and (timestep == timeout): break # if (timestep % 1000) == 0: # log.info("-------------- Simulation cycle --------------") # print(f"-------------- {timestep} ------------------") # print(f'Tasks: {len(self.tasks)}') # if timestep == 516: # breakpoint() self.phase = 'forward' self.sim_list(self.sim_gears) self.phase = 'delta' delta.set() delta.clear() self.phase = 'back' while self._schedule_to_finish: for sim_gear in self._schedule_to_finish.copy(): self._finish(sim_gear) self._schedule_to_finish.remove(sim_gear) self.sim_list(self.sim_gears) self.phase = 'cycle' self.events['before_timestep'](self, timestep) clk.set() clk.clear() # for sim_gear in reversed(self.sim_gears): # if sim_gear in self.delta_ready: # # if hasattr(sim_gear, 'port'): # # print(f'Clock: {sim_gear.gear.name}.{sim_gear.port.basename}') # # else: # # print(f'Clock: {sim_gear.gear.name}') # self.maybe_run_gear(sim_gear, self.delta_ready) for sim_gear in self.done: self.remove(sim_gear) self.done.clear() self.events['after_timestep'](self, timestep) log.info(f"----------- Simulation done ---------------") log.info(f'Elapsed: {time.time() - start_time:.2f}')
############################## SELECT TEST ############################### test_sel = 1 # 0=fir_direct; 1=fir_transposed enable_svgen = 1 # enables systemVerilog generation ########################################################################## # >> used to probe all signals reg['debug/trace'] = ['*'] # >> used to enable JSON file creation for webviewer support reg['debug/webviewer'] = True # set either random or custom seed seed = random.randrange(0, 2**32, 1) # seed = 1379896999 # """Unify all seeds""" log.info(f"Random SEED: {seed}") set_seed(seed) # generate b coefficients b_coef = firwin(8, [0.05, 0.95], width=0.05, pass_zero=False) # generate quantized b coefficients b_coef_type = Fixp[1, 15] b_coef_fixp = [b_coef_type(i) for i in b_coef] # generate random inputs x = np.random.random(size=(10, )) # calculated expected outputs ref = np.convolve(x, b_coef)
def matrix_ops_single(): ########################## DESIGN CONTROLS ########################## num_cols = 8 num_rows = 6 # HINT suppoerted all dimesitions > 1 cols_per_row = 2 # HINT suported values that are divisible with num_colls ########################### TEST CONTROLS ########################### sv_gen = 1 ########################################################################### # set either random or custom seed seed = random.randrange(0, 2**32, 1) # seed = 1379896999 # """Unify all seeds""" log.info(f"Random SEED: {seed}") set_seed(seed) ## input randomization mat1 = np.random.randint(128, size=(num_rows, num_cols)) mat2 = np.random.randint(128, size=(num_rows, num_cols)) mat1 = np.ones((num_rows, num_cols)) mat2 = np.ones((num_rows, num_cols)) # input the constatn value optionally # mat1 = np.empty((num_rows, num_cols)) # mat2 = np.empty((num_rows, num_cols)) # # fill the matrix with the same value # mat1.fill(32767) # mat2.fill(-32768) print("Inputs: ") print(type(mat1)) print(mat1) print(type(mat2)) print(mat2) reg['trace/level'] = 0 reg['gear/memoize'] = False reg['debug/trace'] = ['*'] reg['debug/webviewer'] = True res_list = [] cfg = { "cols_per_row": cols_per_row, "num_rows": num_rows, "num_cols": num_cols, 'cols_per_multiplier': num_rows // cols_per_row } cfg_seq = [cfg] cfg_drv = drv(t=TCfg, seq=cfg_seq) # Add one more dimenstion to the matrix to support input type for design mat1 = mat1.reshape(1, mat1.shape[0], mat1.shape[1]) mat2 = mat2.reshape(mat2.shape[0], 1, mat2.shape[1]) mat1_seq = [mat1] mat2_seq = [mat2] row_t = Queue[Array[Int[16], cfg['num_cols']]] mat1_drv = drv(t=Queue[row_t], seq=mat1_seq) mat2_drv = drv(t=Queue[row_t], seq=mat2_seq) res = matrix_multiplication(cfg_drv, mat1_drv, mat2_drv, cols_per_row=cols_per_row) collect(res, result=res_list) if sv_gen: cosim('/matrix_multiplication', 'verilator', outdir='build/matrix_multiplication/rtl', rebuild=True, timeout=100) sim('build/matrix_multiplication') ## Print raw results results log.info(f'len_res_list: \n{len(res_list)}') try: pg_res = [int(el) for row_chunk in res_list for el in row_chunk] # calc refference data - matrix2 needs to be transposed before doing multiplocation np_res = np.dot(np.squeeze(mat1), np.transpose(mat2.squeeze())) pg_res = np.array(pg_res).reshape(np_res.shape) log.info(f'result: \n{res}') log.info(f'pg_res: \n{pg_res}, shape: {pg_res.shape}') log.info(f'np_res: \n{np_res}, shape: {np_res.shape}') sim_assert( np.equal(pg_res, np_res).all(), "Error in compatring results") log.info("\033[92m //==== PASS ====// \033[90m") except: # printing stack trace traceback.print_exc() log.info("\033[91m //==== FAILED ====// \033[90m")
def after_call_back(self, sim, sim_gear): log.info(f'back') return True
@pytest.mark.parametrize('num_cols', [2, 3, 4, 5, 6, 7, 8]) @pytest.mark.parametrize('num_rows', [2, 3, 4, 5, 6, 7, 8]) @pytest.mark.parametrize('cols_per_row', [1]) @pytest.mark.parametrize('impl', ['high', 'hw']) def test_column_multiplicator(impl, num_cols, num_rows, cols_per_row, seed): set_seed(seed) res_list = [] mat1 = np.random.randint(256, size=(num_cols, num_rows)) mat2 = np.random.randint(256, size=(num_cols, num_rows)) run_matrix(impl, mat1, mat2, cols_per_row, col_only=True) # run individual test with python command if __name__ == '__main__': reg['debug/trace'] = ['*'] reg['debug/webviewer'] = True try: ## HINT : for debugging individual tests test_column_multiplicator('sim', 3, 3, 1, 1) # test_matrix_mult('sim',num_cols=3,num_rows=3,cols_per_row=1,seed=1) # test_matrix_mult_cols('hw', 5, 1) # log.info("\033[92m //==== PASS ====// \033[90m") except: # printing stack trace traceback.print_exc() log.info("\033[91m //==== FAILED ====// \033[90m")
async def check(din, *, ref, cmp=None): """Checks equality of input data with expected. Args: ref: A list of expected values Returns: None If type ``din`` is a :class:`Queue` of certain level, then ``ref`` should generate nested iterables of the same level """ def match_exact(x, y): return x == y if cmp is None: cmp = match_exact iter_ref = iter(ref) ref_seq = iter(()) try: items = [] while True: data = await din.get() items.append(data) try: ref_item = next(ref_seq) except StopIteration: ref_seq = typeseq(din.dtype, next(iter_ref)) ref_item = next(ref_seq) cmp_res = cmp(data, ref_item) if not cmp_res: if cmp is match_exact: v = ErrorVisitor() err = None try: v.visit(data, ref_item) except ValueError as e: err = e if err: log.error( f'mismatch in item #{len(items)}\n {str(err)}') else: breakpoint() else: log.error( f'mismatch in item #{len(items)}. Got: {data}, expected: {ref_item}' ) except GearDone: ref_empty = False try: next(ref_seq) except StopIteration: try: next(iter_ref) except StopIteration: ref_empty = True if ref_empty: log.info(f'Number of matches: {len(items)}') else: log.error( f"mismatch in number of items, got '{len(items)}' but expected '{len(ref)}'. " f"\ngot:\n{textwrap.indent(pprint.pformat(items), ' '*4)}" f"\nexp:\n{textwrap.indent(pprint.pformat(ref), ' '*4)}") except (GearDone, StopIteration): log.error(f"mismatch in number of items {len(items)} vs {len(ref)}. " f"\ngot:\n{textwrap.indent(pprint.pformat(items), ' '*4)}" f"\nexp:\n{textwrap.indent(pprint.pformat(ref), ' '*4)}") raise GearDone
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: log.info(f'Number of matches: {match_cnt:>4}/{cnt:>4}') offending = None if len(items): offending = len(items) if any(not d.empty() for d in din): for i, d in enumerate(din): if d.empty(): offending = i break if offending is not None: log.error(f"Input {offending} didn't produce enough output data") raise e
def run_matrix(impl, mat1, mat2, cols_per_row, col_only: bool = False): reg['trace/level'] = 0 reg['gear/memoize'] = False # Add one more dimension to the matrix to support input type for design mat1 = mat1.reshape(1, mat1.shape[0], mat1.shape[1]) mat2 = mat2.reshape(mat2.shape[0], 1, mat2.shape[1]) # configuration driving cfg = create_valid_cfg(cols_per_row, mat1) cfg_drv = drv(t=TCfg, seq=[cfg]) row_t = Queue[Array[Int[16], cfg['num_cols']]] mat1_drv = drv(t=Queue[row_t], seq=[mat1]) res_list = [] if col_only: # remove the extra dimension that was previously added since colum mult accepts mat2 = np.squeeze(mat2) # for columtn multiplication second operand needs to be only one row mat2_drv = drv(t=row_t, seq=[mat2]) res = column_multiplication(cfg_drv, mat1_drv, mat2_drv) # column multiplication returns result in a queue so flatening makes it a regular list collect(res | flatten, result=res_list) if impl == 'hw': cosim('/column_multiplication', 'verilator', outdir='/tmp/column_multiplication', rebuild=True, timeout=100) else: mat2_drv = drv(t=Queue[row_t], seq=[mat2]) res = matrix_multiplication(cfg_drv, mat1_drv, mat2_drv, cols_per_row=cols_per_row) collect(res, result=res_list) if impl == 'hw': cosim('/matrix_multiplication', 'verilator', outdir='/tmp/matrix_multiplication', rebuild=True, timeout=100) try: sim() # convert PG results into regular 'int' if col_only: pg_res = [int(el) for el in res_list] else: pg_res = [int(el) for row_chunk in res_list for el in row_chunk] # calculate reference NumPy resutls np_res = np.dot(np.squeeze(mat1), np.transpose(mat2.squeeze())) # reshape PG results into the same format as pg_res = np.array(pg_res).reshape(np_res.shape) sim_assert( np.equal(pg_res, np_res).all(), "Error in compatring results") log.info("\033[92m //==== PASS ====// \033[90m") except: # printing stack trace traceback.print_exc() log.info("\033[91m //==== FAILED ====// \033[90m")
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: log.info(f'Verilating...') build(self.top, self.outdir, postsynth=False, lang=self.lang) log.info(f'Done') file_struct = get_file_struct(self.top, self.outdir) tracing_enabled = bool(reg['debug/trace']) if tracing_enabled: 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: 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() 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()