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 28import shlex 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 self.pgo = args.pgo 98 self.pgo_max_cycle = args.pgo_max_cycle 99 self.pgo_emu_args = args.pgo_emu_args 100 self.llvm_profdata = args.llvm_profdata 101 # wave dump path 102 if args.wave_dump is not None: 103 self.set_wave_home(args.wave_dump) 104 else: 105 self.set_wave_home(self.default_wave_home) 106 107 def get_env_variables(self): 108 all_env = { 109 "NOOP_HOME" : self.noop_home, 110 "NEMU_HOME" : self.nemu_home, 111 "WAVE_HOME" : self.wave_home, 112 "AM_HOME" : self.am_home, 113 "DRAMSIM3_HOME": self.dramsim3_home, 114 "MODULEPATH": "/usr/share/Modules/modulefiles:/etc/modulefiles" 115 } 116 return all_env 117 118 def get_chisel_args(self, prefix=None): 119 chisel_args = [ 120 (self.enable_log, "enable-log") 121 ] 122 args = map(lambda x: x[1], filter(lambda arg: arg[0], chisel_args)) 123 if prefix is not None: 124 args = map(lambda x: prefix + x, args) 125 return args 126 127 def get_makefile_args(self): 128 makefile_args = [ 129 (self.threads, "EMU_THREADS"), 130 (self.with_dramsim3, "WITH_DRAMSIM3"), 131 (self.is_release, "RELEASE"), 132 (self.is_spike, "REF"), 133 (self.trace, "EMU_TRACE"), 134 (self.trace_fst, "EMU_TRACE"), 135 (self.config, "CONFIG"), 136 (self.num_cores, "NUM_CORES"), 137 (self.is_mfc, "MFC"), 138 (self.emu_optimize, "EMU_OPTIMIZE"), 139 (self.xprop, "ENABLE_XPROP"), 140 (self.with_chiseldb, "WITH_CHISELDB"), 141 (self.pgo, "PGO_WORKLOAD"), 142 (self.pgo_max_cycle, "PGO_MAX_CYCLE"), 143 (self.pgo_emu_args, "PGO_EMU_ARGS"), 144 (self.llvm_profdata, "LLVM_PROFDATA"), 145 ] 146 args = filter(lambda arg: arg[0] is not None, makefile_args) 147 args = [(shlex.quote(str(arg[0])), arg[1]) for arg in args] # shell escape 148 return args 149 150 def get_emu_args(self): 151 emu_args = [ 152 (self.max_instr, "max-instr"), 153 (self.diff, "diff"), 154 (self.seed, "seed"), 155 (self.ram_size, "ram-size"), 156 ] 157 args = filter(lambda arg: arg[0] is not None, emu_args) 158 return args 159 160 def show(self): 161 print("Extra environment variables:") 162 env = self.get_env_variables() 163 for env_name in env: 164 print(f"{env_name}: {env[env_name]}") 165 print() 166 print("Chisel arguments:") 167 print(" ".join(self.get_chisel_args())) 168 print() 169 print("Makefile arguments:") 170 for val, name in self.get_makefile_args(): 171 print(f"{name}={val}") 172 print() 173 print("emu arguments:") 174 for val, name in self.get_emu_args(): 175 print(f"--{name} {val}") 176 print() 177 178 def __extract_path(self, path, env=None, default=None): 179 if path is None and env is not None: 180 path = os.getenv(env) 181 if path is None and default is not None: 182 path = default 183 path = os.path.realpath(path) 184 return path 185 186 def set_noop_home(self, path): 187 self.noop_home = path 188 189 def set_nemu_home(self, path): 190 self.nemu_home = path 191 192 def set_am_home(self, path): 193 self.am_home = path 194 195 def set_dramsim3_home(self, path): 196 self.dramsim3_home = path 197 198 def set_rvtest_home(self, path): 199 self.rvtest_home = path 200 201 def set_wave_home(self, path): 202 print(f"set wave home to {path}") 203 self.wave_home = path 204 205# XiangShan environment 206class XiangShan(object): 207 def __init__(self, args): 208 self.args = XSArgs(args) 209 self.timeout = args.timeout 210 211 def show(self): 212 self.args.show() 213 214 def make_clean(self): 215 print("Clean up CI workspace") 216 self.show() 217 return_code = self.__exec_cmd(f'make -C $NOOP_HOME clean') 218 return return_code 219 220 def generate_verilog(self): 221 print("Generating XiangShan verilog with the following configurations:") 222 self.show() 223 sim_args = " ".join(self.args.get_chisel_args(prefix="--")) 224 make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args())) 225 return_code = self.__exec_cmd(f'make -C $NOOP_HOME verilog SIM_ARGS="{sim_args}" {make_args}') 226 return return_code 227 228 def generate_sim_verilog(self): 229 print("Generating XiangShan sim-verilog with the following configurations:") 230 self.show() 231 sim_args = " ".join(self.args.get_chisel_args(prefix="--")) 232 make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args())) 233 return_code = self.__exec_cmd(f'make -C $NOOP_HOME sim-verilog SIM_ARGS="{sim_args}" {make_args}') 234 return return_code 235 236 def build_emu(self): 237 print("Building XiangShan emu with the following configurations:") 238 self.show() 239 sim_args = " ".join(self.args.get_chisel_args(prefix="--")) 240 make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args())) 241 return_code = self.__exec_cmd(f'make -C $NOOP_HOME emu -j200 SIM_ARGS="{sim_args}" {make_args}') 242 return return_code 243 244 def build_simv(self): 245 print("Building XiangShan simv with the following configurations") 246 self.show() 247 make_args = " ".join(map(lambda arg: f"{arg[1]}={arg[0]}", self.args.get_makefile_args())) 248 # TODO: make the following commands grouped as unseen scripts 249 return_code = self.__exec_cmd(f'\ 250 eval `/usr/bin/modulecmd zsh load license`;\ 251 eval `/usr/bin/modulecmd zsh load synopsys/vcs/Q-2020.03-SP2`;\ 252 eval `/usr/bin/modulecmd zsh load synopsys/verdi/S-2021.09-SP1`;\ 253 VERDI_HOME=/nfs/tools/synopsys/verdi/S-2021.09-SP1 \ 254 make -C $NOOP_HOME simv {make_args} CONSIDER_FSDB=1') # set CONSIDER_FSDB for compatibility 255 return return_code 256 257 def run_emu(self, workload): 258 print("Running XiangShan emu with the following configurations:") 259 self.show() 260 emu_args = " ".join(map(lambda arg: f"--{arg[1]} {arg[0]}", self.args.get_emu_args())) 261 print("workload:", workload) 262 numa_args = "" 263 if self.args.numa: 264 numa_info = get_free_cores(self.args.threads) 265 numa_args = f"numactl -m {numa_info[0]} -C {numa_info[1]}-{numa_info[2]}" 266 fork_args = "--enable-fork" if self.args.fork else "" 267 diff_args = "--no-diff" if self.args.disable_diff else "" 268 chiseldb_args = "--dump-db" if not self.args.disable_db else "" 269 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}') 270 return return_code 271 272 def run_simv(self, workload): 273 print("Running XiangShan simv with the following configurations:") 274 self.show() 275 diff_args = "$NOOP_HOME/"+ args.diff 276 assert_args = "-assert finish_maxfail=30 -assert global_finish_maxfail=10000" 277 self.__exec_cmd(f'cd $NOOP_HOME/build && ./simv +workload={workload} +diff={diff_args} +dump-wave=fsdb {assert_args} | tee simv.log') 278 with open(f"{self.args.noop_home}/build/simv.log") as f: 279 if "HIT GOOD TRAP" in f.read(): 280 return 0 281 return 1 282 283 def run(self, args): 284 if args.ci is not None: 285 return self.run_ci(args.ci) 286 if args.ci_vcs is not None: 287 return self.run_ci_vcs(args.ci_vcs) 288 actions = [ 289 (args.generate, lambda _ : self.generate_verilog()), 290 (args.vcs_gen, lambda _ : self.generate_sim_verilog()), 291 (args.build, lambda _ : self.build_emu()), 292 (args.vcs_build, lambda _ : self.build_simv()), 293 (args.workload, lambda args: self.run_emu(args.workload)), 294 (args.clean, lambda _ : self.make_clean()) 295 ] 296 valid_actions = map(lambda act: act[1], filter(lambda act: act[0], actions)) 297 for i, action in enumerate(valid_actions): 298 print(f"Action {i}:") 299 ret = action(args) 300 if ret: 301 return ret 302 return 0 303 304 def __exec_cmd(self, cmd): 305 env = dict(os.environ) 306 env.update(self.args.get_env_variables()) 307 print("subprocess call cmd:", cmd) 308 start = time.time() 309 proc = subprocess.Popen(cmd, shell=True, env=env, preexec_fn=os.setsid) 310 try: 311 return_code = proc.wait(self.timeout) 312 end = time.time() 313 print(f"Elapsed time: {end - start} seconds") 314 return return_code 315 except (KeyboardInterrupt, subprocess.TimeoutExpired): 316 os.killpg(os.getpgid(proc.pid), signal.SIGINT) 317 print(f"KeyboardInterrupt or TimeoutExpired.") 318 return 0 319 320 def __get_ci_cputest(self, name=None): 321 base_dir = os.path.join(self.args.am_home, "tests/cputest/build") 322 cputest = os.listdir(base_dir) 323 cputest = filter(lambda x: x.endswith(".bin"), cputest) 324 cputest = map(lambda x: os.path.join(base_dir, x), cputest) 325 return cputest 326 327 def __get_ci_rvtest(self, name=None): 328 base_dir = os.path.join(self.args.rvtest_home, "isa/build") 329 riscv_tests = os.listdir(base_dir) 330 riscv_tests = filter(lambda x: x.endswith(".bin"), riscv_tests) 331 all_rv_tests = ["rv64ui", "rv64um", "rv64ua", "rv64uf", "rv64ud"] 332 riscv_tests = filter(lambda x: x[:6] in all_rv_tests, riscv_tests) 333 riscv_tests = map(lambda x: os.path.join(base_dir, x), riscv_tests) 334 return riscv_tests 335 336 def __get_ci_misc(self, name=None): 337 base_dir = "/nfs/home/share/ci-workloads" 338 workloads = [ 339 "bitmanip/bitMisc.bin", 340 "crypto/crypto-riscv64-noop.bin", 341 "coremark_rv64gc_o2/coremark-riscv64-xs.bin", 342 "coremark_rv64gc_o3/coremark-riscv64-xs.bin", 343 "coremark_rv64gcb_o3/coremark-riscv64-xs.bin", 344 "ext_intr/amtest-riscv64-xs.bin", 345 "cache-alias/aliastest-riscv64-xs.bin", 346 "Svinval/rv64mi-p-svinval.bin", 347 "pmp/pmp.riscv.bin", 348 "pmp/pmp-am/amtest-riscv64-xs.bin", 349 "pmp/hugepage-pmp-atom/amtest-riscv64-xs.bin", 350 "asid/asid.bin", 351 "isa_misc/xret_clear_mprv.bin", 352 "isa_misc/satp_ppn.bin", 353 "cache-management/softprefetchtest-riscv64-xs.bin" 354 ] 355 misc_tests = map(lambda x: os.path.join(base_dir, x), workloads) 356 return misc_tests 357 358 def __get_ci_mc(self, name=None): 359 base_dir = "/nfs/home/share/ci-workloads" 360 workloads = [ 361 "dualcoretest/ldvio-riscv64-xs.bin" 362 ] 363 mc_tests = map(lambda x: os.path.join(base_dir, x), workloads) 364 return mc_tests 365 366 def __get_ci_nodiff(self, name=None): 367 base_dir = "/nfs/home/share/ci-workloads" 368 workloads = [ 369 "cache-management/cacheoptest-riscv64-xs.bin" 370 ] 371 tests = map(lambda x: os.path.join(base_dir, x), workloads) 372 return tests 373 374 def __am_apps_path(self, bench): 375 filename = f"{bench}-riscv64-noop.bin" 376 return [os.path.join(self.args.am_home, "apps", bench, "build", filename)] 377 378 def __get_ci_workloads(self, name): 379 workloads = { 380 "linux-hello": "bbl.bin", 381 "linux-hello-smp": "bbl.bin", 382 "linux-hello-opensbi": "fw_payload.bin", 383 "linux-hello-smp-opensbi": "fw_payload.bin", 384 "linux-hello-new": "bbl.bin", 385 "linux-hello-smp-new": "bbl.bin", 386 "povray": "_700480000000_.gz", 387 "mcf": "_17520000000_.gz", 388 "xalancbmk": "_266100000000_.gz", 389 "gcc": "_39720000000_.gz", 390 "namd": "_434640000000_.gz", 391 "milc": "_103620000000_.gz", 392 "lbm": "_140840000000_.gz", 393 "gromacs": "_275480000000_.gz", 394 "wrf": "_1916220000000_.gz", 395 "astar": "_122060000000_.gz" 396 } 397 if name in workloads: 398 return [os.path.join("/nfs/home/share/ci-workloads", name, workloads[name])] 399 # select a random SPEC checkpoint 400 assert(name == "random") 401 all_cpt = [ 402 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gcb_o2_20m/take_cpt", 403 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gcb_o3_20m/take_cpt", 404 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gc_o2_20m/take_cpt", 405 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gc_o2_50m/take_cpt", 406 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gcb_o2_20m/take_cpt", 407 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gcb_o3_20m/take_cpt", 408 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gc_o2_50m/take_cpt", 409 "/nfs-nvme/home/share/checkpoints_profiles/spec17_speed_rv64gcb_o3_20m/take_cpt" 410 ] 411 all_json = [ 412 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gcb_o2_20m/json/simpoint_summary.json", 413 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gcb_o3_20m/simpoint_summary.json", 414 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gc_o2_20m/simpoint_summary.json", 415 "/nfs-nvme/home/share/checkpoints_profiles/spec06_rv64gc_o2_50m/simpoint_summary.json", 416 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gcb_o2_20m/simpoint_summary.json", 417 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gcb_o3_20m/simpoint_summary.json", 418 "/nfs-nvme/home/share/checkpoints_profiles/spec17_rv64gc_o2_50m/simpoint_summary.json", 419 "/nfs-nvme/home/share/checkpoints_profiles/spec17_speed_rv64gcb_o3_20m/simpoint_summary.json" 420 ] 421 assert(len(all_cpt) == len(all_json)) 422 cpt_path, json_path = random.choice(list(zip(all_cpt, all_json))) 423 all_gcpt = load_all_gcpt(cpt_path, json_path) 424 return [random.choice(all_gcpt)] 425 426 def run_ci(self, test): 427 all_tests = { 428 "cputest": self.__get_ci_cputest, 429 "riscv-tests": self.__get_ci_rvtest, 430 "misc-tests": self.__get_ci_misc, 431 "mc-tests": self.__get_ci_mc, 432 "nodiff-tests": self.__get_ci_nodiff, 433 "microbench": self.__am_apps_path, 434 "coremark": self.__am_apps_path 435 } 436 for target in all_tests.get(test, self.__get_ci_workloads)(test): 437 print(target) 438 ret = self.run_emu(target) 439 if ret: 440 if self.args.default_wave_home != self.args.wave_home: 441 print("copy wave file to " + self.args.wave_home) 442 self.__exec_cmd(f"cp $NOOP_HOME/build/*.vcd $WAVE_HOME") 443 self.__exec_cmd(f"cp $NOOP_HOME/build/emu $WAVE_HOME") 444 self.__exec_cmd(f"cp $NOOP_HOME/build/rtl/SimTop.v $WAVE_HOME") 445 self.__exec_cmd(f"cp $NOOP_HOME/build/*.db $WAVE_HOME") 446 return ret 447 return 0 448 449 def run_ci_vcs(self, test): 450 all_tests = { 451 "cputest": self.__get_ci_cputest, 452 "riscv-tests": self.__get_ci_rvtest, 453 "misc-tests": self.__get_ci_misc, 454 "mc-tests": self.__get_ci_mc, 455 "nodiff-tests": self.__get_ci_nodiff, 456 "microbench": self.__am_apps_path, 457 "coremark": self.__am_apps_path 458 } 459 for target in all_tests.get(test, self.__get_ci_workloads)(test): 460 print(target) 461 ret = self.run_simv(target) 462 if ret: 463 if self.args.default_wave_home != self.args.wave_home: 464 print("copy wave file to " + self.args.wave_home) 465 self.__exec_cmd(f"cp $NOOP_HOME/build/*.fsdb $WAVE_HOME") 466 self.__exec_cmd(f"cp $NOOP_HOME/build/simv $WAVE_HOME") 467 self.__exec_cmd(f"cp $NOOP_HOME/build/rtl/SimTop.v $WAVE_HOME") 468 self.__exec_cmd(f"cp $NOOP_HOME/build/*.db $WAVE_HOME") 469 return ret 470 return 0 471 472def get_free_cores(n): 473 while True: 474 # To avoid potential conflicts, we allow CI to use SMT. 475 num_logical_core = psutil.cpu_count(logical=False) 476 core_usage = psutil.cpu_percent(interval=1, percpu=True) 477 num_window = num_logical_core // n 478 for i in range(num_window): 479 window_usage = core_usage[i * n : i * n + n] 480 if sum(window_usage) < 30 * n and True not in map(lambda x: x > 90, window_usage): 481 return (((i * n) % 128)// 64, i * n, i * n + n - 1) 482 print(f"No free {n} cores found. CPU usage: {core_usage}\n") 483 484if __name__ == "__main__": 485 parser = argparse.ArgumentParser(description='Python wrapper for XiangShan') 486 parser.add_argument('workload', nargs='?', type=str, default="", 487 help='input workload file in binary format') 488 # actions 489 parser.add_argument('--build', action='store_true', help='build XS emu') 490 parser.add_argument('--generate', action='store_true', help='generate XS verilog') 491 parser.add_argument('--vcs-gen', action='store_true', help='generate XS sim verilog for vcs') 492 parser.add_argument('--vcs-build', action='store_true', help='build XS simv') 493 parser.add_argument('--ci', nargs='?', type=str, const="", help='run CI tests') 494 parser.add_argument('--ci-vcs', nargs='?', type=str, const="", help='run CI tests on simv') 495 parser.add_argument('--clean', action='store_true', help='clean up XiangShan CI workspace') 496 parser.add_argument('--timeout', nargs='?', type=int, default=None, help='timeout (in seconds)') 497 # environment variables 498 parser.add_argument('--nemu', nargs='?', type=str, help='path to nemu') 499 parser.add_argument('--am', nargs='?', type=str, help='path to nexus-am') 500 parser.add_argument('--dramsim3', nargs='?', type=str, help='path to dramsim3') 501 parser.add_argument('--rvtest', nargs='?', type=str, help='path to riscv-tests') 502 parser.add_argument('--wave-dump', nargs='?', type=str , help='path to dump wave') 503 # chisel arguments 504 parser.add_argument('--enable-log', action='store_true', help='enable log') 505 parser.add_argument('--num-cores', type=int, help='number of cores') 506 # makefile arguments 507 parser.add_argument('--release', action='store_true', help='enable release') 508 parser.add_argument('--spike', action='store_true', help='enable spike diff') 509 parser.add_argument('--with-dramsim3', action='store_true', help='enable dramsim3') 510 parser.add_argument('--threads', nargs='?', type=int, help='number of emu threads') 511 parser.add_argument('--trace', action='store_true', help='enable vcd waveform') 512 parser.add_argument('--trace-fst', action='store_true', help='enable fst waveform') 513 parser.add_argument('--config', nargs='?', type=str, help='config') 514 parser.add_argument('--mfc', action='store_true', help='use mfc') 515 parser.add_argument('--emu-optimize', nargs='?', type=str, help='verilator optimization letter') 516 parser.add_argument('--xprop', action='store_true', help='enable xprop for vcs') 517 # emu arguments 518 parser.add_argument('--numa', action='store_true', help='use numactl') 519 parser.add_argument('--diff', nargs='?', default="./ready-to-run/riscv64-nemu-interpreter-so", type=str, help='nemu so') 520 parser.add_argument('--max-instr', nargs='?', type=int, help='max instr') 521 parser.add_argument('--disable-fork', action='store_true', help='disable lightSSS') 522 parser.add_argument('--no-diff', action='store_true', help='disable difftest') 523 parser.add_argument('--ram-size', nargs='?', type=str, help='manually set simulation memory size (8GB by default)') 524 # both makefile and emu arguments 525 parser.add_argument('--no-db', action='store_true', help='disable chiseldb dump') 526 parser.add_argument('--pgo', nargs='?', type=str, help='workload for pgo (null to disable pgo)') 527 parser.add_argument('--pgo-max-cycle', nargs='?', default=400000, type=int, help='maximun cycle to train pgo') 528 parser.add_argument('--pgo-emu-args', nargs='?', default='--no-diff', type=str, help='emu arguments for pgo') 529 parser.add_argument('--llvm-profdata', nargs='?', type=str, help='corresponding llvm-profdata command of clang to compile emu, do not set with GCC') 530 531 args = parser.parse_args() 532 533 xs = XiangShan(args) 534 ret = xs.run(args) 535 536 sys.exit(ret) 537