1#*************************************************************************************** 2# Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC) 3# Copyright (c) 2020-2024 Institute of Computing Technology, Chinese Academy of Sciences 4# Copyright (c) 2020-2021 Peng Cheng Laboratory 5# 6# XiangShan is licensed under Mulan PSL v2. 7# You can use this software according to the terms and conditions of the Mulan PSL v2. 8# You may obtain a copy of Mulan PSL v2 at: 9# http://license.coscl.org.cn/MulanPSL2 10# 11# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 12# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 13# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 14# 15# See the Mulan PSL v2 for more details. 16#*************************************************************************************** 17 18# Simple version of xiangshan python wrapper 19 20import argparse 21import json 22import os 23import random 24import signal 25import subprocess 26import sys 27import time 28 29import psutil 30 31 32def load_all_gcpt(gcpt_path, json_path): 33 all_gcpt = [] 34 with open(json_path) as f: 35 data = json.load(f) 36 for benchspec in data: 37 for point in data[benchspec]: 38 weight = data[benchspec][point] 39 gcpt = os.path.join(gcpt_path, "_".join([benchspec, point, weight])) 40 bin_dir = os.path.join(gcpt, "0") 41 bin_file = list(os.listdir(bin_dir)) 42 assert(len(bin_file) == 1) 43 bin_path = os.path.join(bin_dir, bin_file[0]) 44 assert(os.path.isfile(bin_path)) 45 all_gcpt.append(bin_path) 46 return all_gcpt 47 48class XSArgs(object): 49 script_path = os.path.realpath(__file__) 50 # default path to the repositories 51 noop_home = os.path.join(os.path.dirname(script_path), "..") 52 nemu_home = os.path.join(noop_home, "../NEMU") 53 am_home = os.path.join(noop_home, "../nexus-am") 54 dramsim3_home = os.path.join(noop_home, "../DRAMsim3") 55 rvtest_home = os.path.join(noop_home, "../riscv-tests") 56 default_wave_home = os.path.join(noop_home, "build") 57 wave_home = default_wave_home 58 59 def __init__(self, args): 60 # all path environment variables that should be set 61 all_path = [ 62 # (python argument, environment variable, default, target function) 63 (None, "NOOP_HOME", self.noop_home, self.set_noop_home), 64 (args.nemu, "NEMU_HOME", self.nemu_home, self.set_nemu_home), 65 (args.am, "AM_HOME", self.am_home, self.set_am_home), 66 (args.dramsim3, "DRAMSIM3_HOME", self.dramsim3_home, self.set_dramsim3_home), 67 (args.rvtest, "RVTEST_HOME", self.rvtest_home, self.set_rvtest_home), 68 ] 69 for (arg_in, env, default, set_func) in all_path: 70 set_func(self.__extract_path(arg_in, env, default)) 71 # Chisel arguments 72 self.enable_log = args.enable_log 73 self.num_cores = args.num_cores 74 # Makefile arguments 75 self.threads = args.threads 76 self.with_dramsim3 = 1 if args.with_dramsim3 else None 77 self.is_release = 1 if args.release else None 78 self.is_spike = "Spike" if args.spike else None 79 self.trace = 1 if args.trace or not args.disable_fork and not args.trace_fst else None 80 self.trace_fst = "fst" if args.trace_fst else None 81 self.config = args.config 82 self.is_mfc = 1 if args.mfc else None 83 self.emu_optimize = args.emu_optimize 84 self.xprop = 1 if args.xprop else None 85 self.with_chiseldb = 0 if args.no_db else None 86 # emu arguments 87 self.max_instr = args.max_instr 88 self.ram_size = args.ram_size 89 self.seed = random.randint(0, 9999) 90 self.numa = args.numa 91 self.diff = args.diff 92 if args.spike and "nemu" in args.diff: 93 self.diff = self.diff.replace("nemu-interpreter", "spike") 94 self.fork = not args.disable_fork 95 self.disable_diff = args.no_diff 96 self.disable_db = args.no_db 97 # wave dump path 98 if args.wave_dump is not None: 99 self.set_wave_home(args.wave_dump) 100 else: 101 self.set_wave_home(self.default_wave_home) 102 103 def get_env_variables(self): 104 all_env = { 105 "NOOP_HOME" : self.noop_home, 106 "NEMU_HOME" : self.nemu_home, 107 "WAVE_HOME" : self.wave_home, 108 "AM_HOME" : self.am_home, 109 "DRAMSIM3_HOME": self.dramsim3_home, 110 "MODULEPATH": "/usr/share/Modules/modulefiles:/etc/modulefiles" 111 } 112 return all_env 113 114 def get_chisel_args(self, prefix=None): 115 chisel_args = [ 116 (self.enable_log, "enable-log") 117 ] 118 args = map(lambda x: x[1], filter(lambda arg: arg[0], chisel_args)) 119 if prefix is not None: 120 args = map(lambda x: prefix + x, args) 121 return args 122 123 def get_makefile_args(self): 124 makefile_args = [ 125 (self.threads, "EMU_THREADS"), 126 (self.with_dramsim3, "WITH_DRAMSIM3"), 127 (self.is_release, "RELEASE"), 128 (self.is_spike, "REF"), 129 (self.trace, "EMU_TRACE"), 130 (self.trace_fst, "EMU_TRACE"), 131 (self.config, "CONFIG"), 132 (self.num_cores, "NUM_CORES"), 133 (self.is_mfc, "MFC"), 134 (self.emu_optimize, "EMU_OPTIMIZE"), 135 (self.xprop, "ENABLE_XPROP"), 136 (self.with_chiseldb, "WITH_CHISELDB") 137 ] 138 args = filter(lambda arg: arg[0] is not None, makefile_args) 139 return args 140 141 def get_emu_args(self): 142 emu_args = [ 143 (self.max_instr, "max-instr"), 144 (self.diff, "diff"), 145 (self.seed, "seed"), 146 (self.ram_size, "ram-size"), 147 ] 148 args = filter(lambda arg: arg[0] is not None, emu_args) 149 return args 150 151 def show(self): 152 print("Extra environment variables:") 153 env = self.get_env_variables() 154 for env_name in env: 155 print(f"{env_name}: {env[env_name]}") 156 print() 157 print("Chisel arguments:") 158 print(" ".join(self.get_chisel_args())) 159 print() 160 print("Makefile arguments:") 161 for val, name in self.get_makefile_args(): 162 print(f"{name}={val}") 163 print() 164 print("emu arguments:") 165 for val, name in self.get_emu_args(): 166 print(f"--{name} {val}") 167 print() 168 169 def __extract_path(self, path, env=None, default=None): 170 if path is None and env is not None: 171 path = os.getenv(env) 172 if path is None and default is not None: 173 path = default 174 path = os.path.realpath(path) 175 return path 176 177 def set_noop_home(self, path): 178 self.noop_home = path 179 180 def set_nemu_home(self, path): 181 self.nemu_home = path 182 183 def set_am_home(self, path): 184 self.am_home = path 185 186 def set_dramsim3_home(self, path): 187 self.dramsim3_home = path 188 189 def set_rvtest_home(self, path): 190 self.rvtest_home = path 191 192 def set_wave_home(self, path): 193 print(f"set wave home to {path}") 194 self.wave_home = path 195 196# XiangShan environment 197class XiangShan(object): 198 def __init__(self, args): 199 self.args = XSArgs(args) 200 self.timeout = args.timeout 201 202 def show(self): 203 self.args.show() 204 205 def make_clean(self): 206 print("Clean up CI workspace") 207 self.show() 208 return_code = self.__exec_cmd(f'make -C $NOOP_HOME clean') 209 return return_code 210 211 def generate_verilog(self): 212 print("Generating XiangShan verilog with the following configurations:") 213 self.show() 214 sim_args = " ".join(self.args.get_chisel_args(prefix="--")) 215 make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args())) 216 return_code = self.__exec_cmd(f'make -C $NOOP_HOME verilog SIM_ARGS="{sim_args}" {make_args}') 217 return return_code 218 219 def generate_sim_verilog(self): 220 print("Generating XiangShan sim-verilog with the following configurations:") 221 self.show() 222 sim_args = " ".join(self.args.get_chisel_args(prefix="--")) 223 make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args())) 224 return_code = self.__exec_cmd(f'make -C $NOOP_HOME sim-verilog SIM_ARGS="{sim_args}" {make_args}') 225 return return_code 226 227 def build_emu(self): 228 print("Building XiangShan emu with the following configurations:") 229 self.show() 230 sim_args = " ".join(self.args.get_chisel_args(prefix="--")) 231 make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args())) 232 return_code = self.__exec_cmd(f'make -C $NOOP_HOME emu -j200 SIM_ARGS="{sim_args}" {make_args}') 233 return return_code 234 235 def build_simv(self): 236 print("Building XiangShan simv with the following configurations") 237 self.show() 238 make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args())) 239 # TODO: make the following commands grouped as unseen scripts 240 return_code = self.__exec_cmd(f'\ 241 eval `/usr/bin/modulecmd zsh load license`;\ 242 eval `/usr/bin/modulecmd zsh load synopsys/vcs/Q-2020.03-SP2`;\ 243 eval `/usr/bin/modulecmd zsh load synopsys/verdi/S-2021.09-SP1`;\ 244 VERDI_HOME=/nfs/tools/synopsys/verdi/S-2021.09-SP1 \ 245 make -C $NOOP_HOME simv {make_args} CONSIDER_FSDB=1') # set CONSIDER_FSDB for compatibility 246 return return_code 247 248 def run_emu(self, workload): 249 print("Running XiangShan emu with the following configurations:") 250 self.show() 251 emu_args = " ".join(map(lambda arg: f"--{arg[1]} {arg[0]}", self.args.get_emu_args())) 252 print("workload:", workload) 253 numa_args = "" 254 if self.args.numa: 255 numa_info = get_free_cores(self.args.threads) 256 numa_args = f"numactl -m {numa_info[0]} -C {numa_info[1]}-{numa_info[2]}" 257 fork_args = "--enable-fork" if self.args.fork else "" 258 diff_args = "--no-diff" if self.args.disable_diff else "" 259 chiseldb_args = "--dump-db" if not self.args.disable_db else "" 260 return_code = self.__exec_cmd(f'ulimit -s {32 * 1024}; {numa_args} $NOOP_HOME/build/emu -i {workload} {emu_args} {fork_args} {diff_args} {chiseldb_args}') 261 return return_code 262 263 def run_simv(self, workload): 264 print("Running XiangShan simv with the following configurations:") 265 self.show() 266 diff_args = "$NOOP_HOME/"+ args.diff 267 assert_args = "-assert finish_maxfail=30 -assert global_finish_maxfail=10000" 268 return_code = self.__exec_cmd(f'cd $NOOP_HOME/build && ./simv +workload={workload} +diff={diff_args} +dump-wave=fsdb {assert_args}') 269 return return_code 270 271 def run(self, args): 272 if args.ci is not None: 273 return self.run_ci(args.ci) 274 if args.ci_vcs is not None: 275 return self.run_ci_vcs(args.ci_vcs) 276 actions = [ 277 (args.generate, lambda _ : self.generate_verilog()), 278 (args.vcs_gen, lambda _ : self.generate_sim_verilog()), 279 (args.build, lambda _ : self.build_emu()), 280 (args.vcs_build, lambda _ : self.build_simv()), 281 (args.workload, lambda args: self.run_emu(args.workload)), 282 (args.clean, lambda _ : self.make_clean()) 283 ] 284 valid_actions = map(lambda act: act[1], filter(lambda act: act[0], actions)) 285 for i, action in enumerate(valid_actions): 286 print(f"Action {i}:") 287 ret = action(args) 288 if ret: 289 return ret 290 return 0 291 292 def __exec_cmd(self, cmd): 293 env = dict(os.environ) 294 env.update(self.args.get_env_variables()) 295 print("subprocess call cmd:", cmd) 296 start = time.time() 297 proc = subprocess.Popen(cmd, shell=True, env=env, preexec_fn=os.setsid) 298 try: 299 return_code = proc.wait(self.timeout) 300 end = time.time() 301 print(f"Elapsed time: {end - start} seconds") 302 return return_code 303 except (KeyboardInterrupt, subprocess.TimeoutExpired): 304 os.killpg(os.getpgid(proc.pid), signal.SIGINT) 305 print(f"KeyboardInterrupt or TimeoutExpired.") 306 return 0 307 308 def __get_ci_cputest(self, name=None): 309 base_dir = os.path.join(self.args.am_home, "tests/cputest/build") 310 cputest = os.listdir(base_dir) 311 cputest = filter(lambda x: x.endswith(".bin"), cputest) 312 cputest = map(lambda x: os.path.join(base_dir, x), cputest) 313 return cputest 314 315 def __get_ci_rvtest(self, name=None): 316 base_dir = os.path.join(self.args.rvtest_home, "isa/build") 317 riscv_tests = os.listdir(base_dir) 318 riscv_tests = filter(lambda x: x.endswith(".bin"), riscv_tests) 319 all_rv_tests = ["rv64ui", "rv64um", "rv64ua", "rv64uf", "rv64ud"] 320 riscv_tests = filter(lambda x: x[:6] in all_rv_tests, riscv_tests) 321 riscv_tests = map(lambda x: os.path.join(base_dir, x), riscv_tests) 322 return riscv_tests 323 324 def __get_ci_misc(self, name=None): 325 base_dir = "/nfs/home/share/ci-workloads" 326 workloads = [ 327 "bitmanip/bitMisc.bin", 328 "crypto/crypto-riscv64-noop.bin", 329 "coremark_rv64gc_o2/coremark-riscv64-xs.bin", 330 "coremark_rv64gc_o3/coremark-riscv64-xs.bin", 331 "coremark_rv64gcb_o3/coremark-riscv64-xs.bin", 332 "ext_intr/amtest-riscv64-xs.bin", 333 "cache-alias/aliastest-riscv64-xs.bin", 334 "Svinval/rv64mi-p-svinval.bin", 335 "pmp/pmp.riscv.bin", 336 "pmp/pmp-am/amtest-riscv64-xs.bin", 337 "pmp/hugepage-pmp-atom/amtest-riscv64-xs.bin", 338 "asid/asid.bin", 339 "isa_misc/xret_clear_mprv.bin", 340 "isa_misc/satp_ppn.bin", 341 "cache-management/softprefetchtest-riscv64-xs.bin" 342 ] 343 misc_tests = map(lambda x: os.path.join(base_dir, x), workloads) 344 return misc_tests 345 346 def __get_ci_mc(self, name=None): 347 base_dir = "/nfs/home/share/ci-workloads" 348 workloads = [ 349 "dualcoretest/ldvio-riscv64-xs.bin" 350 ] 351 mc_tests = map(lambda x: os.path.join(base_dir, x), workloads) 352 return mc_tests 353 354 def __get_ci_nodiff(self, name=None): 355 base_dir = "/nfs/home/share/ci-workloads" 356 workloads = [ 357 "cache-management/cacheoptest-riscv64-xs.bin" 358 ] 359 tests = map(lambda x: os.path.join(base_dir, x), workloads) 360 return tests 361 362 def __am_apps_path(self, bench): 363 filename = f"{bench}-riscv64-noop.bin" 364 return [os.path.join(self.args.am_home, "apps", bench, "build", filename)] 365 366 def __get_ci_workloads(self, name): 367 workloads = { 368 "linux-hello": "bbl.bin", 369 "linux-hello-smp": "bbl.bin", 370 "linux-hello-opensbi": "fw_payload.bin", 371 "linux-hello-smp-opensbi": "fw_payload.bin", 372 "linux-hello-new": "bbl.bin", 373 "linux-hello-smp-new": "bbl.bin", 374 "povray": "_700480000000_.gz", 375 "mcf": "_17520000000_.gz", 376 "xalancbmk": "_266100000000_.gz", 377 "gcc": "_39720000000_.gz", 378 "namd": "_434640000000_.gz", 379 "milc": "_103620000000_.gz", 380 "lbm": "_140840000000_.gz", 381 "gromacs": "_275480000000_.gz", 382 "wrf": "_1916220000000_.gz", 383 "astar": "_122060000000_.gz" 384 } 385 if name in workloads: 386 return [os.path.join("/nfs/home/share/ci-workloads", name, workloads[name])] 387 # select a random SPEC checkpoint 388 assert(name == "random") 389 all_cpt = [ 390 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gcb_o2_20m/take_cpt", 391 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gcb_o3_20m/take_cpt", 392 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gc_o2_20m/take_cpt", 393 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gc_o2_50m/take_cpt", 394 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gcb_o2_20m/take_cpt", 395 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gcb_o3_20m/take_cpt", 396 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gc_o2_50m/take_cpt", 397 "/nfs-nvme/home/share/checkpoints_profiles/spec17_speed_rv64gcb_o3_20m/take_cpt" 398 ] 399 all_json = [ 400 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gcb_o2_20m/json/simpoint_summary.json", 401 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gcb_o3_20m/simpoint_summary.json", 402 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gc_o2_20m/simpoint_summary.json", 403 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gc_o2_50m/simpoint_summary.json", 404 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gcb_o2_20m/simpoint_summary.json", 405 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gcb_o3_20m/simpoint_summary.json", 406 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gc_o2_50m/simpoint_summary.json", 407 "/nfs-nvme/home/share/checkpoints_profiles/spec17_speed_rv64gcb_o3_20m/simpoint_summary.json" 408 ] 409 assert(len(all_cpt) == len(all_json)) 410 cpt_path, json_path = random.choice(list(zip(all_cpt, all_json))) 411 all_gcpt = load_all_gcpt(cpt_path, json_path) 412 return [random.choice(all_gcpt)] 413 414 def run_ci(self, test): 415 all_tests = { 416 "cputest": self.__get_ci_cputest, 417 "riscv-tests": self.__get_ci_rvtest, 418 "misc-tests": self.__get_ci_misc, 419 "mc-tests": self.__get_ci_mc, 420 "nodiff-tests": self.__get_ci_nodiff, 421 "microbench": self.__am_apps_path, 422 "coremark": self.__am_apps_path 423 } 424 for target in all_tests.get(test, self.__get_ci_workloads)(test): 425 print(target) 426 ret = self.run_emu(target) 427 if ret: 428 if self.args.default_wave_home != self.args.wave_home: 429 print("copy wave file to " + self.args.wave_home) 430 self.__exec_cmd(f"cp $NOOP_HOME/build/*.vcd $WAVE_HOME") 431 self.__exec_cmd(f"cp $NOOP_HOME/build/emu $WAVE_HOME") 432 self.__exec_cmd(f"cp $NOOP_HOME/build/rtl/SimTop.v $WAVE_HOME") 433 self.__exec_cmd(f"cp $NOOP_HOME/build/*.db $WAVE_HOME") 434 return ret 435 return 0 436 437 def run_ci_vcs(self, test): 438 all_tests = { 439 "cputest": self.__get_ci_cputest, 440 "riscv-tests": self.__get_ci_rvtest, 441 "misc-tests": self.__get_ci_misc, 442 "mc-tests": self.__get_ci_mc, 443 "nodiff-tests": self.__get_ci_nodiff, 444 "microbench": self.__am_apps_path, 445 "coremark": self.__am_apps_path 446 } 447 for target in all_tests.get(test, self.__get_ci_workloads)(test): 448 print(target) 449 ret = self.run_simv(target) 450 if ret: 451 if self.args.default_wave_home != self.args.wave_home: 452 print("copy wave file to " + self.args.wave_home) 453 self.__exec_cmd(f"cp $NOOP_HOME/build/*.fsdb $WAVE_HOME") 454 self.__exec_cmd(f"cp $NOOP_HOME/build/simv $WAVE_HOME") 455 self.__exec_cmd(f"cp $NOOP_HOME/build/rtl/SimTop.v $WAVE_HOME") 456 self.__exec_cmd(f"cp $NOOP_HOME/build/*.db $WAVE_HOME") 457 return ret 458 return 0 459 460def get_free_cores(n): 461 while True: 462 # To avoid potential conflicts, we allow CI to use SMT. 463 num_logical_core = psutil.cpu_count(logical=False) 464 core_usage = psutil.cpu_percent(interval=1, percpu=True) 465 num_window = num_logical_core // n 466 for i in range(num_window): 467 window_usage = core_usage[i * n : i * n + n] 468 if sum(window_usage) < 30 * n and True not in map(lambda x: x > 90, window_usage): 469 return (((i * n) % 128)// 64, i * n, i * n + n - 1) 470 print(f"No free {n} cores found. CPU usage: {core_usage}\n") 471 472if __name__ == "__main__": 473 parser = argparse.ArgumentParser(description='Python wrapper for XiangShan') 474 parser.add_argument('workload', nargs='?', type=str, default="", 475 help='input workload file in binary format') 476 # actions 477 parser.add_argument('--build', action='store_true', help='build XS emu') 478 parser.add_argument('--generate', action='store_true', help='generate XS verilog') 479 parser.add_argument('--vcs-gen', action='store_true', help='generate XS sim verilog for vcs') 480 parser.add_argument('--vcs-build', action='store_true', help='build XS simv') 481 parser.add_argument('--ci', nargs='?', type=str, const="", help='run CI tests') 482 parser.add_argument('--ci-vcs', nargs='?', type=str, const="", help='run CI tests on simv') 483 parser.add_argument('--clean', action='store_true', help='clean up XiangShan CI workspace') 484 parser.add_argument('--timeout', nargs='?', type=int, default=None, help='timeout (in seconds)') 485 # environment variables 486 parser.add_argument('--nemu', nargs='?', type=str, help='path to nemu') 487 parser.add_argument('--am', nargs='?', type=str, help='path to nexus-am') 488 parser.add_argument('--dramsim3', nargs='?', type=str, help='path to dramsim3') 489 parser.add_argument('--rvtest', nargs='?', type=str, help='path to riscv-tests') 490 parser.add_argument('--wave-dump', nargs='?', type=str , help='path to dump wave') 491 # chisel arguments 492 parser.add_argument('--enable-log', action='store_true', help='enable log') 493 parser.add_argument('--num-cores', type=int, help='number of cores') 494 # makefile arguments 495 parser.add_argument('--release', action='store_true', help='enable release') 496 parser.add_argument('--spike', action='store_true', help='enable spike diff') 497 parser.add_argument('--with-dramsim3', action='store_true', help='enable dramsim3') 498 parser.add_argument('--threads', nargs='?', type=int, help='number of emu threads') 499 parser.add_argument('--trace', action='store_true', help='enable vcd waveform') 500 parser.add_argument('--trace-fst', action='store_true', help='enable fst waveform') 501 parser.add_argument('--config', nargs='?', type=str, help='config') 502 parser.add_argument('--mfc', action='store_true', help='use mfc') 503 parser.add_argument('--emu-optimize', nargs='?', type=str, help='verilator optimization letter') 504 parser.add_argument('--xprop', action='store_true', help='enable xprop for vcs') 505 # emu arguments 506 parser.add_argument('--numa', action='store_true', help='use numactl') 507 parser.add_argument('--diff', nargs='?', default="./ready-to-run/riscv64-nemu-interpreter-so", type=str, help='nemu so') 508 parser.add_argument('--max-instr', nargs='?', type=int, help='max instr') 509 parser.add_argument('--disable-fork', action='store_true', help='disable lightSSS') 510 parser.add_argument('--no-diff', action='store_true', help='disable difftest') 511 parser.add_argument('--ram-size', nargs='?', type=str, help='manually set simulation memory size (8GB by default)') 512 # both makefile and emu arguments 513 parser.add_argument('--no-db', action='store_true', help='disable chiseldb dump') 514 515 args = parser.parse_args() 516 517 xs = XiangShan(args) 518 ret = xs.run(args) 519 520 sys.exit(ret) 521