def tb(config=config.BonfireConfig(), hexFile="", elfFile="", sigFile=""): clock = Signal(bool(0)) reset = ResetSignal(0, active=1, isasync=False) dbus = bonfire_interfaces.DbusBundle(config) wb_master = bonfire_interfaces.Wishbone_master_bundle() wb_bfm = Wishbone_bfm() clk_driver = ClkDriver(clock, period=10) bram_port_a = ram_dp.RamPort32(readOnly=True) bram_port_b = ram_dp.RamPort32() soc_i = bonfire_core_ex.bonfireCoreExtendedInterface(wb_master, dbus, bram_port_a, bram_port_b, clock, reset, config=config) ram = ram_dp.DualportedRam(hexFile) ram_i = ram.ram_instance(bram_port_a, bram_port_b, clock) mon_i = monitor_instance(ram.ram, dbus, clock, sigFile=sigFile, elfFile=elfFile) bfm_i = wb_bfm.Wishbone_check(wb_master, clock, reset) return instances()
def tb(): clk_driver = ClkDriver(clock) inst = RegisterFile(clock, reg_portA, reg_portB, reg_writePort) inst.convert(hdl='VHDL', std_logic_ports=True, path='vhdl_gen', name="regfile") @instance def stimulus(): yield clock.posedge for i in range(0, 32): reg_writePort.wa.next = i reg_portA.ra.next = i reg_portB.ra.next = i reg_writePort.wd.next = 0x55aa0000 | i reg_writePort.we.next = 1 yield clock.posedge reg_writePort.we.next = 0 for i in range(0, 32): reg_portA.ra.next = i reg_portB.ra.next = i yield clock.posedge print(reg_portA.rd, reg_portB.rd) print("Simulation finished") raise StopSimulation return instances()
def tb_cache_way(test_conversion=False): from rtl.cache.cache_way import cache_way_instance, CacheWayBundle from rtl.cache.config import CacheConfig conf = CacheConfig() conf.print_config() clock = Signal(bool(0)) clk_driver = ClkDriver(clock) reset = ResetSignal(0, active=1, isasync=False) w = CacheWayBundle(conf) cw_inst = cache_way_instance(w, clock, reset) if test_conversion: cw_inst.convert(hdl='VHDL', std_logic_ports=True, path='vhdl_gen', name="cache_way") def miss_and_update(adr): print("tag miss and update with adr:{}".format(adr)) conf.print_address(adr) w.adr.next = adr w.en.next = 1 yield clock.posedge # wait for response while not (w.hit or w.miss): yield clock.posedge assert w.miss and not w.hit, "Miss=1 hit=0 expected" assert not w.tag_valid assert not w.dirty_miss # Write Tag w.we.next = True w.valid.next = True w.dirty.next = True yield clock.posedge w.we.next = False yield clock.posedge assert w.tag_valid, "after tag update: tag_valid should be set" assert w.hit, "after tag update: hit should be set" assert not w.miss, "after tag update: miss should not be set" print("OK") @instance def stimulus(): yield clock.posedge for i in range(0, 16): # conf.tag_ram_size): adr = conf.create_address(0, i, 0) yield miss_and_update(adr) raise StopSimulation return instances()
def tb_barrel_shift_pipelined(): clk_driver = ClkDriver(clock) shift_right = Signal(bool(0)) dut = barrel_shifter.shift_pipelined(clock, reset, d_in, d_o, shift_in, shift_right, fill_i, en_i, ready_o, 3) dut.convert(hdl='VHDL', std_logic_ports=True, path='vhdl_gen') @instance def stimulus(): reset.next = True yield delay(40) reset.next = False yield delay(40) print("zero fill") fill_i.next = 0 for i in range(shift_in.max): shift_in.next = i en_i.next = 1 yield clock.posedge en_i.next = 0 while ready_o == 0: yield clock.posedge print(i, bin(d_o, 32)) assert (d_o == d_in << i) yield clock.posedge print("Right shift logical") d_in.next = 0x80000000 shift_right.next = True for i in range(shift_in.max): shift_in.next = i en_i.next = 1 yield clock.posedge en_i.next = 0 while ready_o == 0: yield clock.posedge print(i, bin(d_o, 32)) assert (d_o == d_in >> i) yield clock.posedge print("Simulation finished") raise StopSimulation return instances()
def tb_tagram(test_conversion=False): from rtl.cache.cache_way import TagDataBundle from rtl.cache.tag_ram import tag_ram_instance conf = CacheConfig(**kwargs) clock = Signal(bool(0)) reset = ResetSignal(0, active=1, isasync=False) clk_driver = ClkDriver(clock) t_in = TagDataBundle(10) t_out = TagDataBundle(10) we = Signal(bool(0)) adr = Signal(modbv(0)[conf.line_select_adr_bits:]) t_r_i = tag_ram_instance(t_in, t_out, we, adr, clock, reset, conf) if test_conversion: t_r_i.convert(hdl='VHDL', std_logic_ports=True, path='vhdl_gen', name="tag_ram") @instance def stimulus(): yield clock.posedge # Write data we.next = True for i in range(0, 16): adr.next = i t_in.address.next = i t_in.valid.next = True t_in.dirty.next = False yield clock.posedge fs = "address: {address}, valid:{valid}, dirty:{dirty} @{adr}" we.next = False adr.next = 0 yield clock.posedge for i in range(0, 16): adr.next = i yield clock.posedge print(fs.format(adr=adr, **t_out.__dict__)) print("Simulation finished") raise StopSimulation return instances()
def tb(c_shifter_mode="behavioral", test_conversion=False): clk_driver = ClkDriver(clock) #inst=alu.alu() inst = AluBundle.alu(alu, clock, reset, c_shifter_mode) if c_shifter_mode != "behavioral" and test_conversion: inst.convert(hdl='VHDL', std_logic_ports=True, path='vhdl_gen', name="alu_" + c_shifter_mode) def test_op(cmd): alu.funct3_i.next = cmd["f3"] alu.funct7_6_i.next = cmd["f7"] alu.op1_i.next = cmd["a"] alu.op2_i.next = cmd["b"] alu.en_i.next = True yield clock.posedge if not alu.valid_o: print(cmd["c"], "pipelined") alu.en_i.next = False while not alu.valid_o: yield clock.posedge print("{} {} {} result: {}".format(alu.op1_i, cmd["c"], alu.op2_i, alu.res_o)) shouldbe = modbv(0)[32:] r = cmd["r"] if type(r) == types.FunctionType: shouldbe[32:] = r(alu.op1_i, alu.op2_i) else: shouldbe[32:] = r assert alu.res_o == shouldbe, "error, should be {}".format( shouldbe.unsigned()) return @instance def stimulus(): yield clock.posedge for cmd in commands: yield test_op(cmd) print("Simulation finished") raise StopSimulation return instances()
def tb(config=config.BonfireConfig(), test_conversion=False): clock = Signal(bool(0)) reset = ResetSignal(0, active=1, isasync=False) cmd_index = Signal(intbv(0)[32:]) debug = DebugOutputBundle(config) out = BackendOutputBundle() datatbus = loadstore.DbusBundle(config=config) backend = SimpleBackend(config=config) fetch = FetchInputBundle(config=config) frontend = dummy_fetch_unit() fu_i = frontend.createInstance(fetch, clock, reset) clk_driver = ClkDriver(clock) dut = backend.backend(fetch, frontend, datatbus, clock, reset, out, debug) if test_conversion: dut.convert(hdl='VHDL', std_logic_ports=False, path='vhdl_gen', name="backend") # Simulated Data RAM mem = sim_ram() mem_i = mem.ram_interface(ram, datatbus, clock, reset) @always_comb def tb_comb(): result_o.next = debug.result_o rd_o.next = debug.rd_adr_o we_o.next = debug.reg_we_o jump_o.next = backend.execute.jump_o jump_dest_o.next = backend.execute.jump_dest_o take_branch.next = debug.jump and debug.jump_exec def check(cmd): t = cmd["t"] if type(t) == types.FunctionType: if t(): print("OK") else: print("FAIL") assert StopSimulation print("----") @always_seq(clock.posedge, reset=reset) def commit_check(): if cmd_index >= len(commands): print("Simulation finished") raise StopSimulation if debug.valid_o: cmd = commands[cmd_index] if we_o: print("at {}ns {}: commmit to reg {} value {}".format( now(), cmd["source"], abi_name(rd_o), result_o)) else: print("at {}ns {}: commmit without reg write".format( now(), cmd["source"])) check(cmd) cmd_index.next = cmd_index + 1 if debug.jump_exec: cmd = commands[cmd_index] print("at {}ns: {}, do: {}".format(now(), cmd["source"], debug.jump)) check(cmd) # In case of a not taken branch increment command counter now, because there will be no jump_o signal if not debug.jump: cmd_index.next = cmd_index + 1 if jump_o: cmd = commands[cmd_index] print("at {}ns: {}, destination: {}".format( now(), cmd["source"], jump_dest_o)) check(cmd) return instances()
def tb(config=config.BonfireConfig(),test_conversion=False): clock=Signal(bool(0)) reset = ResetSignal(1, active=1, isasync=False) ibus = DbusBundle(config=config,readOnly=True) debug=DebugOutputBundle(config) out = BackendOutputBundle() dbus = DbusBundle(config=config) fetch_bundle = FetchInputBundle(config=config) fetch_unit = FetchUnit(config=config) backend = SimpleBackend(config=config) clk_driver= ClkDriver(clock) dut=fetch_unit.SimpleFetchUnit(fetch_bundle,ibus,clock,reset) if test_conversion: dut.convert(hdl='VHDL',std_logic_ports=False,path='vhdl_gen', name="fetch" ) # processor Backend i_backend = backend.backend(fetch_bundle,fetch_unit,dbus,clock,reset,out,debug) # Simulated Code RAM c_mem = sim_ram() c_mem.setLatency(1) c_mem_i = c_mem.ram_interface(code_ram,ibus,clock,reset,readOnly=True) # Simulated Data RAM d_mem = sim_ram() d_mem.setLatency(1) d_mem_i = d_mem.ram_interface(data_ram,dbus,clock,reset) @always_comb def comb(): fetch_unit.jump_dest_i.next=out.jump_dest_o fetch_unit.jump_i.next = out.jump_o fetch_unit.stall_i.next = out.busy_o result_o.next =debug.result_o rd_o.next = debug.rd_adr_o we_o.next = debug.reg_we_o jump_o.next = out.jump_o jump_dest_o.next = out.jump_dest_o take_branch.next = debug.jump and debug.jump_exec current_ip_r = Signal(intbv(0)) @always_seq(clock.posedge,reset=reset) def sim_observe(): if backend.execute.taken: t_ip = backend.decode.debug_current_ip_o print("@{}ns exc: {} : {} ".format(now(),t_ip,backend.decode.debug_word_o)) assert code_ram[t_ip>>2]==backend.decode.debug_word_o, "pc vs ram content mismatch" assert backend.decode.next_ip_o == t_ip + 4, "next_ip vs. current_ip mismatch" current_ip_r.next = t_ip >> 2 # if out.jump_o: # raise StopSimulation jump_cnt = Signal(intbv(0)) def check(cmd): t=cmd["t"] if type(t) == types.FunctionType: if t(): print("OK") else: print("FAIL") raise StopSimulation print("----") @always_seq(clock.posedge,reset=reset) def commit_check(): if jump_cnt > 0: print("Simulation finished") raise StopSimulation if backend.execute.taken: idx = backend.decode.debug_current_ip_o >> 2 else: idx = current_ip_r if debug.valid_o: cmd = commands[ idx] if debug.reg_we_o: print("@{}ns {}: commmit to reg {} value {}".format(now(), cmd["source"], abi_name(debug.rd_adr_o), debug.result_o)) else: print("@{}ns {}: commmit without reg write".format(now(), cmd["source"])) check(cmd) if debug.jump_exec: cmd = commands[idx] print ("at {}ns: {}, do: {}".format(now(),cmd["source"],debug.jump)) check(cmd) if jump_o: cmd = commands[idx] print ("at {}ns: {}, destination: {}".format(now(),cmd["source"], jump_dest_o )) jump_cnt.next = jump_cnt + 1 @instance def stimulus(): # Copy code to RAM i=0 for cmd in commands: code_ram[i].next=cmd["opcode"] i += 1 for i in range(1,3): yield clock.posedge reset.next=0 return instances()
def tb_cache( test_conversion=False, master_data_width=128, line_size=4, # Line size in MASTER_DATA_WIDTH words cache_size_m_words=2048, # Cache Size in MASTER_DATA_WIDTH Bit words address_bits=30, # Number of bits of chacheable address range num_ways=1, # Number of cache ways pipelined=False, verbose=False): from rtl.cache.cache import CacheMasterWishboneBundle, CacheControlBundle, cache_instance from rtl.bonfire_interfaces import DbusBundle from tb.sim_wb_burst_ram import ram_interface config = CacheConfig(master_data_width=master_data_width, line_size=line_size, cache_size_m_words=cache_size_m_words, address_bits=address_bits, num_ways=num_ways) clock = Signal(bool(0)) reset = ResetSignal(0, active=1, isasync=False) clk_driver = ClkDriver(clock) # our simulated RAM is four times the cache size, this is enough for write testing... ram = [ Signal(modbv(0)[config.master_data_width:]) for ii in range(0, config.cache_size_m_words * 4) ] wb_master = CacheMasterWishboneBundle(config) db_slave = DbusBundle(len=32) pattern_mode = Signal(bool(True)) ram_i = ram_interface(ram, wb_master, pattern_mode, clock, config) c_i = cache_instance(db_slave, wb_master, clock, reset, config) if test_conversion: c_i.convert(hdl='VHDL', std_logic_ports=True, path='vhdl_gen', name="cache") address_queue = [] queue_len = Signal(intbv(0)) @always(clock.posedge) def monitor_ack(): if db_slave.ack_i: ack_address = address_queue.pop(0) queue_len.next = len(address_queue) assert queue_len > 0, "ack raised on empy queue" if ack_address[2] == "r": if verbose: print_t("read_ack: {}:{}".format(ack_address[0], db_slave.db_rd)) if ack_address[1] != None: assert db_slave.db_rd == ack_address[1], \ "@{}: read from {}, verify failed expected: {}, read:{}".format(now(), hex(ack_address[0]), hex(ack_address[1]),db_slave.db_rd) else: if verbose: print_t("write ack at {}:".format(ack_address[0])) assert not db_slave.stall_i, "@{} db_slave ack_i while stall_i raised".format( now()) def db_read(address, verify=None, blocking=False): # pipelined read start, does not wait on ack db_slave.en_o.next = True db_slave.we_o.next = 0 db_slave.adr_o.next = address address_queue.append((address, verify, "r")) queue_len.next = len(address_queue) yield clock.posedge # Block on stall while db_slave.stall_i: yield clock.posedge db_slave.en_o.next = False if blocking: while not db_slave.ack_i: yield clock.posedge def read_loop(start_adr, length, pipelined=False): print("Start loop at:") config.print_address(start_adr) for i in range(0, length): adr = modbv((start_adr + i) << 2)[32:] yield db_read(adr, adr, not pipelined) def db_write(address, data, blocking=False): yield clock.posedge db_slave.en_o.next = True db_slave.we_o.next = 0b1111 db_slave.adr_o.next = address db_slave.db_wr.next = data address_queue.append((address, None, "w")) queue_len.next = len(address_queue) yield clock.posedge # Block on stall while db_slave.stall_i: yield clock.posedge db_slave.en_o.next = False db_slave.we_o.next = 0 if blocking: while not db_slave.ack_i: yield clock.posedge db_slave.en_o.next = False # deassert en after first clock @instance def stimulus(): config.print_config() line_size = 2**config.cl_bits_slave # Line size in slave words def loop_test(pipelined): print_t("Loop test pipelined" if pipelined else "Loop test") for i in range(0, 1): yield clock.posedge yield clock.posedge print_t("Read two lines") yield read_loop(config.create_address(0, 0, 0), line_size * 2, pipelined) print_t( "Read two lines with same line index, but different tag value" ) yield read_loop(config.create_address(1, 0, 0), line_size * 2, pipelined) #print_t("Read from last line of cache") #yield read_loop(config.create_address(0,2**config.line_select_adr_bits-1,0),line_size,pipelined) def basic_write_test(pipelined): blocking = not pipelined pattern_mode.next = False yield clock.posedge print_t("Basic write test") yield db_write(0, 0xdeadbeef, blocking) yield db_write(4, 0xabcd8000, blocking) yield db_read(0, 0xdeadbeef, blocking) yield db_read(4, 0xabcd8000, blocking) print_t("Write back test") adr = config.create_address(1, 0, 0) << 2 yield db_write(adr, 0x55aa55ff, blocking) yield db_read(adr, 0x55aa55ff, blocking) print_t("cross check") yield db_read(0, 0xdeadbeef, blocking) yield clock.posedge yield db_read(0xc, 0xc, not pipelined) yield loop_test(pipelined) yield basic_write_test(pipelined) yield clock.posedge raise StopSimulation return instances()
def tb(test_conversion=False): clk_driver = ClkDriver(clock) inst = DecodeBundle.decoder(dec, clock, reset) if test_conversion: inst.convert(hdl='VHDL', std_logic_ports=True, path='vhdl_gen', name="decode") cmd_index = Signal(intbv(0)) rs1 = Signal(intbv(0)[5:]) rs2 = Signal(intbv(0)[5:]) @always_seq(clock.posedge, reset=reset) def decode_output(): # Save register addresses if dec.en_i: rs1.next = dec.rs1_adr_o rs2.next = dec.rs2_adr_o if dec.valid_o: if cmd_index >= len(commands): print("Simulation finished") raise StopSimulation cmd = commands[cmd_index] print("{} at {} ns".format(cmd["source"], now())) print("rs1: {}, rs2: {} rd:{}".format(abi_name(rs1), abi_name(rs2), abi_name(dec.rd_adr_o))) print("funct3: {} funct7: {}".format(bin(dec.funct3_onehot_o, 8), bin(dec.funct7_o, 7))) print("op1: {} op2: {}".format(dec.op1_o, dec.op2_o, 7)) if dec.branch_cmd: print("Branch target: {}".format(hex(dec.jump_dest_o))) t = cmd["t"] if type(t) == types.FunctionType: if t(dec, rs1, rs2): print("OK") else: print("FAIL") print("----") cmd_index.next = cmd_index + 1 def test_op(cmd): dec.word_i.next = cmd["opcode"] ip = cmd.get("current_ip", 0) dec.current_ip_i.next = ip dec.next_ip_i.next = ip + 4 dec.en_i.next = True yield clock.posedge return @instance def stimulus(): for cmd in commands: yield test_op(cmd) return instances()
def tb(config=config.BonfireConfig(),test_conversion=False): print("Testing LSU with loadstore_outstanding={}, registered_read_stage={} ".format(config.loadstore_outstanding,config.registered_read_stage)) clock=Signal(bool(0)) reset = ResetSignal(0, active=1, isasync=False) clk_driver= ClkDriver(clock) bus = DbusBundle(config) ls = LoadStoreBundle(config) dut=LoadStoreBundle.LoadStoreUnit(ls,bus,clock,reset) if test_conversion: dut.convert(hdl='VHDL',std_logic_ports=False,path='vhdl_gen', name="loadstore" ) ram = [Signal(modbv(0)[32:]) for ii in range(0, ram_size)] mem = sim_ram() mem_i = mem.ram_interface(ram,bus,clock,reset) cnt = Signal(intbv(0)) fetch_index = Signal(intbv(0)) def sw_test(): fetch_index.next = 0 yield clock.posedge ls.funct3_i.next = StoreFunct3.RV32_F3_SW ls.store_i.next = True ls.op1_i.next = 0 ls.rd_i.next = 5 countdown=len(store_words) while countdown>0: if ls.valid_o: countdown -= 1 if fetch_index<len(store_words): ls.en_i.next = True if not ls.busy_o: ls.displacement_i.next = fetch_index * 4 ls.op2_i.next = store_words[fetch_index] fetch_index.next += 1 else: if not ls.busy_o: ls.en_i.next=False yield clock.posedge # Verify memory content i=0 for v in store_words: print("write check ram[{}]: {}=={} ".format(i,ram[i],hex(v))) assert ram[i]==v, "loadstore sw test failed" i += 1 def lw_test(): yield clock.posedge ls.funct3_i.next = LoadFunct3.RV32_F3_LW ls.store_i.next= False ls.op1_i.next=0 count=len(store_words) finish=False i=Signal(intbv(0)) while not finish: if not ls.busy_o: ls.displacement_i.next= i*4 ls.rd_i.next= i # "Misuse" rd register as index into test data i.next += 1 ls.en_i.next = i<count if ls.valid_o: assert ls.we_o, "loadstore lw test, ls.we_o not set" print("read check x{}: {} == {}".format(ls.rd_o,ls.result_o,hex(store_words[ls.rd_o]))) assert(ls.result_o==store_words[ls.rd_o]), "loadstore lw test failed" finish = ls.rd_o==count-1 yield clock.posedge def sb_test(): yield clock.posedge ls.funct3_i.next = StoreFunct3.RV32_F3_SB ls.store_i.next = True ls.op1_i.next = 5<<2 # Base Memory address for test ls.rd_i.next = 5 countdown=8 displacement=0 while countdown>0: if ls.valid_o: countdown -= 1 if displacement<8: ls.en_i.next = True if not ls.busy_o: ls.displacement_i.next = displacement # Extract next byte from store_words ls.op2_i.next = store_words[displacement>>2] >> (displacement % 4* 8) displacement += 1 else: if not ls.busy_o: ls.en_i.next=False yield clock.posedge print("Store Byte result: {} {}".format(ram[5],ram[6])) assert (ram[5]==store_words[0] and ram[6]==store_words[1]), "loadstore sb test failed" def sh_test(): yield clock.posedge ls.funct3_i.next = StoreFunct3.RV32_F3_SH ls.store_i.next = True ls.op1_i.next = 7<<2 # Base Memory address for test ls.rd_i.next = 5 countdown=4 displacement=0 while countdown>0: if ls.valid_o: countdown -= 1 if displacement<8: ls.en_i.next = True if not ls.busy_o: ls.displacement_i.next = displacement # Extract next half word from store_words ls.op2_i.next = store_words[displacement>>2] >> ((displacement >> 1 & 1) * 16) displacement += 2 else: if not ls.busy_o: ls.en_i.next=False yield clock.posedge print("Store word result: {} {}".format(ram[7],ram[8])) assert(ram[7]==store_words[0] and ram[8]==store_words[1]), "loadstore sh test failed" def load_single(base,displacement,funct3): ls.funct3_i.next = funct3 ls.store_i.next = False ls.op1_i.next = base ls.rd_i.next = 5 ls.displacement_i.next = displacement ls.en_i.next = True yield clock.posedge while ls.busy_o: yield clock.posedge ls.en_i.next = False while not ls.valid_o: yield clock.posedge print(now()) def wait_valid(): while ls.valid_o: yield clock.posedge def _check(a,b,message): s= "{}: checking {}=={}".format(message,hex(a),hex(b)) assert a==b, s + " failed" print(s," OK") def _check_we(): assert ls.we_o,"Register we signal not set" def load_other_test(): """ Test lb,lbu,lh,lhu """ assert ram[3]==0x705a8000, "load_other: ram[3] does not contain the expected content" yield clock.posedge print("Testing lbu") yield load_single(3<<2,1,LoadFunct3.RV32_F3_LBU) ## Should read the ff byte _check_we() _check(ls.result_o,0x80,"lbu test" ) print("Testing lb negative") yield load_single(3<<2,1,LoadFunct3.RV32_F3_LB) ## Should read and sign extend the ff byte _check_we() _check(ls.result_o,0xffffff80,"lb negative test" ) print("Testing lb positive") yield load_single(3<<2,2,LoadFunct3.RV32_F3_LB) ## Should read and sign extend the 55 byte _check_we() _check(ls.result_o,0x5a,"lb positive test" ) print("Testing lhu") yield load_single(3<<2,0,LoadFunct3.RV32_F3_LHU) ## Should read the ff00 hword _check_we() _check(ls.result_o,0x8000,"lhu test" ) print("Testing lh negative") yield load_single(3<<2,0,LoadFunct3.RV32_F3_LH) ## Should read and sign extend the ff00 hword _check_we() _check(ls.result_o,0xffff8000,"lh negative test" ) print("Testing lh positive") yield load_single(3<<2,2,LoadFunct3.RV32_F3_LH) ## Should read and sign extend the 0055 hword _check_we() _check(ls.result_o,0x705a,"lh positive test" ) def run_all(): yield sw_test() yield wait_valid() yield lw_test() yield wait_valid() yield sb_test() yield wait_valid() yield sh_test() yield wait_valid() yield load_other_test() def clear_ram(): for m in ram: m.next = 0 yield clock.posedge @instance def stimulus(): mem.setLatency(1) yield run_all() yield clear_ram() print("Run with RAM wait state") mem.setLatency(2) yield run_all() raise StopSimulation return instances()