# All rights reserved. # # The license below extends only to copyright in the software and shall # not be construed as granting a license to any other intellectual # property including but not limited to intellectual property relating # to a hardware implementation of the functionality of the software # licensed hereunder. You may use the software subject to the license # terms below provided that you ensure that this notice is replicated # unmodified and in its entirety in all distributions of the software, # modified or unmodified, in source code or in binary form. # # Copyright (c) 2021 Huawei International # Copyright (c) 2012-2014 Mark D. Hill and David A. Wood # Copyright (c) 2009-2011 Advanced Micro Devices, Inc. # Copyright (c) 2006-2007 The Regents of The University of Michigan # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer; # redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution; # neither the name of the copyright holders nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import argparse import sys from os import path import m5 from m5.defines import buildEnv from m5.objects import * from m5.util import addToPath, fatal, warn from m5.util.fdthelper import * addToPath("../../") from ruby import Ruby from common.FSConfig import * from common.SysPaths import * from common.Benchmarks import * from common import Simulation from common import CacheConfig from common import CpuConfig from common import MemConfig from common import ObjectList from common.Caches import * from common import Options # ------------------------- Usage Instructions ------------------------- # # Common system confirguration options (cpu types, num cpus, checkpointing # etc.) should be supported # # Ruby not supported in this config file. Not tested on RISC-V FS Linux (as # of 25 March 2021). # # Options (Full System): # --kernel (required): Bootloader + kernel binary (e.g. bbl with # linux kernel payload) # --disk-image (optional): Path to disk image file. Not needed if using # ramfs (might run into issues though). # --virtio-rng (optional): Enable VirtIO entropy source device # --command-line (optional): Specify to override default. # --dtb-filename (optional): Path to DTB file. Auto-generated if empty. # --bare-metal (boolean): Use baremetal Riscv (default False). Use this # if bbl is built with "--with-dts" option. # (do not forget to include bootargs in dts file) # # Not Used: # --command-line-file, --script, --frame-capture, --os-type, --timesync, # --dual, -b, --etherdump, --root-device, --ruby # ----------------------- DTB Generation Function ---------------------- # def generateMemNode(state, mem_range): node = FdtNode(f"memory@{int(mem_range.start):x}") node.append(FdtPropertyStrings("device_type", ["memory"])) node.append( FdtPropertyWords( "reg", state.addrCells(mem_range.start) + state.sizeCells(mem_range.size()), ) ) return node def generateDtb(system): state = FdtState(addr_cells=2, size_cells=2, cpu_cells=1) root = FdtNode("/") root.append(state.addrCellsProperty()) root.append(state.sizeCellsProperty()) root.appendCompatible(["riscv-virtio"]) for mem_range in system.mem_ranges: root.append(generateMemNode(state, mem_range)) sections = [*system.cpu, system.platform] for section in sections: for node in section.generateDeviceTree(state): if node.get_name() == root.get_name(): root.merge(node) else: root.append(node) fdt = Fdt() fdt.add_rootnode(root) fdt.writeDtsFile(path.join(m5.options.outdir, "device.dts")) fdt.writeDtbFile(path.join(m5.options.outdir, "device.dtb")) # ----------------------------- Add Options ---------------------------- # parser = argparse.ArgumentParser() Options.addCommonOptions(parser) Options.addFSOptions(parser) parser.add_argument( "--bare-metal", action="store_true", help="Provide the raw system without the linux specific bits", ) parser.add_argument( "--dtb-filename", action="store", type=str, help="Specifies device tree blob file to use with device-tree-" "enabled kernels", ) parser.add_argument( "--virtio-rng", action="store_true", help="Enable VirtIORng device" ) # ---------------------------- Parse Options --------------------------- # args = parser.parse_args() # CPU and Memory (CPUClass, mem_mode, FutureClass) = Simulation.setCPUClass(args) MemClass = Simulation.setMemClass(args) np = args.num_cpus # ---------------------------- Setup System ---------------------------- # # Default Setup system = System() mdesc = SysConfig( disks=args.disk_image, rootdev=args.root_device, mem=args.mem_size, os_type=args.os_type, ) system.mem_mode = mem_mode system.mem_ranges = [AddrRange(start=0x80000000, size=mdesc.mem())] if args.bare_metal: system.workload = RiscvBareMetal() system.workload.bootloader = args.kernel else: system.workload = RiscvLinux() system.workload.object_file = args.kernel system.iobus = IOXBar() system.membus = MemBus() system.system_port = system.membus.cpu_side_ports # HiFive Platform system.platform = HiFive() # RTCCLK (Set to 100MHz for faster simulation) system.platform.rtc = RiscvRTC(frequency=Frequency("100MHz")) system.platform.clint.int_pin = system.platform.rtc.int_pin # VirtIOMMIO if args.disk_image: image = CowDiskImage(child=RawDiskImage(read_only=True), read_only=False) image.child.image_file = mdesc.disks()[0] system.platform.disk = RiscvMmioVirtIO( vio=VirtIOBlock(image=image), interrupt_id=0x8, pio_size=4096, pio_addr=0x10008000, ) # VirtIORng if args.virtio_rng: system.platform.rng = RiscvMmioVirtIO( vio=VirtIORng(), interrupt_id=0x8, pio_size=4096, pio_addr=0x10007000 ) system.bridge = Bridge(delay="50ns") system.bridge.mem_side_port = system.iobus.cpu_side_ports system.bridge.cpu_side_port = system.membus.mem_side_ports system.bridge.ranges = system.platform._off_chip_ranges() system.platform.attachOnChipIO(system.membus) system.platform.attachOffChipIO(system.iobus) system.platform.attachPlic() system.platform.setNumCores(np) # ---------------------------- Default Setup --------------------------- # # Set the cache line size for the entire system system.cache_line_size = args.cacheline_size # Create a top-level voltage domain system.voltage_domain = VoltageDomain(voltage=args.sys_voltage) # Create a source clock for the system and set the clock period system.clk_domain = SrcClockDomain( clock=args.sys_clock, voltage_domain=system.voltage_domain ) # Create a CPU voltage domain system.cpu_voltage_domain = VoltageDomain() # Create a source clock for the CPUs and set the clock period system.cpu_clk_domain = SrcClockDomain( clock=args.cpu_clock, voltage_domain=system.cpu_voltage_domain ) system.workload.object_file = args.kernel # NOTE: Not yet tested if args.script is not None: system.readfile = args.script system.init_param = args.init_param system.cpu = [ CPUClass(clk_domain=system.cpu_clk_domain, cpu_id=i) for i in range(np) ] if args.caches or args.l2cache: # By default the IOCache runs at the system clock system.iocache = IOCache(addr_ranges=system.mem_ranges) system.iocache.cpu_side = system.iobus.mem_side_ports system.iocache.mem_side = system.membus.cpu_side_ports elif not args.external_memory_system: system.iobridge = Bridge(delay="50ns", ranges=system.mem_ranges) system.iobridge.cpu_side_port = system.iobus.mem_side_ports system.iobridge.mem_side_port = system.membus.cpu_side_ports # Sanity check if args.simpoint_profile: if not ObjectList.is_noncaching_cpu(CPUClass): fatal("SimPoint generation should be done with atomic cpu") if np > 1: fatal("SimPoint generation not supported with more than one CPUs") for i in range(np): if args.simpoint_profile: system.cpu[i].addSimPointProbe(args.simpoint_interval) if args.checker: system.cpu[i].addCheckerCpu() if not ObjectList.is_kvm_cpu(CPUClass): if args.bp_type: bpClass = ObjectList.bp_list.get(args.bp_type) system.cpu[i].branchPred = bpClass() if args.indirect_bp_type: IndirectBPClass = ObjectList.indirect_bp_list.get( args.indirect_bp_type ) system.cpu[i].branchPred.indirectBranchPred = IndirectBPClass() system.cpu[i].createThreads() # ----------------------------- PMA Checker ---------------------------- # uncacheable_range = [ *system.platform._on_chip_ranges(), *system.platform._off_chip_ranges(), ] # PMA checker can be defined at system-level (system.pma_checker) # or MMU-level (system.cpu[0].mmu.pma_checker). It will be resolved # by RiscvTLB's Parent.any proxy for cpu in system.cpu: cpu.mmu.pma_checker = PMAChecker(uncacheable=uncacheable_range) # --------------------------- DTB Generation --------------------------- # if not args.bare_metal: if args.dtb_filename: system.workload.dtb_filename = args.dtb_filename else: generateDtb(system) system.workload.dtb_filename = path.join( m5.options.outdir, "device.dtb" ) # Default DTB address if bbl is bulit with --with-dts option system.workload.dtb_addr = 0x87E00000 # Linux boot command flags if args.command_line: system.workload.command_line = args.command_line else: kernel_cmd = ["console=ttyS0", "root=/dev/vda", "ro"] system.workload.command_line = " ".join(kernel_cmd) # ---------------------------- Default Setup --------------------------- # if ( args.elastic_trace_en and args.checkpoint_restore == None and not args.fast_forward ): CpuConfig.config_etrace(CPUClass, system.cpu, args) CacheConfig.config_cache(args, system) MemConfig.config_mem(args, system) root = Root(full_system=True, system=system) Simulation.setWorkCountOptions(system, args) Simulation.run(args, root, system, FutureClass)