FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Gem5のチュートリアル "Learning Gem5"をやってみる(Part-2)

Gem5の勉強のために、チュートリアルを1からやってみることにした。

www.gem5.org

さらに、システムが正しく動作するためにさらにいくつかのポートを接続する。

I/OコントローラをCPUとメモリバスに接続する必要がある。

メモリバスに対して特殊なポートを接続する必要がある。このポートはシステムが読み書きを行うためのポートとなる。

system.cpu.createInterruptController()
system.cpu.interrupts[0].pio = system.membus.mem_side_ports
system.cpu.interrupts[0].int_requestor = system.membus.cpu_side_ports
system.cpu.interrupts[0].int_responder = system.membus.mem_side_ports

system.system_port = system.membus.cpu_side_ports

次にメモリコントローラを作成して、メモリバスに接続する。単純なDDR3コントローラを作成して、システム中のメモリ領域全体を制御するようにする。

system.mem_ctrl = MemCtrl()
system.mem_ctrl.dram = DDR3_1600_8x8()
system.mem_ctrl.dram.range = system.mem_ranges[0]
system.mem_ctrl.port = system.membus.mem_side_ports

これらの接続を行った結果、最終的にシステム構成は以下のようになる。


  • Syscallエミュレーションモード(SE Mode)
  • Full systemエミュレーションモード(FS Mode)
    • 全体のハードウェアシステムをエミュレーションするモード。仮想マシン上で動作させるのに似ている。
    • システム全体をモデリングし、ページテーブルなどのOSの相互作用をエミュレーションするためには、FSモードを使用するべき。

まず、プロセスを作成し、そのプロセスに実行したいコマンドを設定する。次にCPUに対してそのプロセスのコマンドを使用するように設定し、CPU内に機能実行コンテキストを作成する。

binary = 'tests/test-progs/hello/bin/x86/linux/hello'

# for gem5 V21 and beyond
system.workload = SEWorkload.init_compatible(binary)

process = Process()
process.cmd = [binary]
system.cpu.workload = process
system.cpu.createThreads()

最後に、システムをインスタンス化して実行を開始する。最初に、rootオブジェクトを作成する。

root = Root(full_system = False, system = system)
m5.instantiate()

最後に、シミュレーションを開始する。

print("Beginning simulation!")
exit_event = m5.simulate()

シミュレーションを終了すると、システムの状態を調査する。

print('Exiting @ tick {} because {}'
      .format(m5.curTick(), exit_event.getCause()))

このスクリプトを使って、シミュレーションを行う。

build/X86/gem5.opt configs/tutorial/part1/simple.py

スクリプト全体をまとめると、以下のようになる。

# """ This file creates a barebones system and executes 'hello', a simple Hello
# World application.
# See Part 1, Chapter 2: Creating a simple configuration script in the
# learning_gem5 book for more information about this script.
# IMPORTANT: If you modify this file, it's likely that the Learning gem5 book
#            also needs to be updated. For now, email Jason <power.jg@gmail.com>
# This script uses the X86 ISA. `simple-arm.py` and `simple-riscv.py` may be
# referenced as examples of scripts which utilize the ARM and RISC-V ISAs
# respectively.
# このスクリプトでは、ベアボーンシステムを立ち上げてシンプルな`Hello World`アプリケーションんである
# 'hello'を実行する。
# Part 1, Chapter 2: Creating simple configuration script in the learning_gem5 bookの内容である。
# このスクリプトでは、X86 ISAを使用している。ARMとRISC-V ISAを使用する場合には、
# `simple-arm.py`および`simple-riscv.py`を使用する。
# """

# gem5をビルドした際に作成したm5ライブラリをインポートする
import m5
# すべてのSimObjectsをインポートする
from m5.objects import *
# シミュレーション用のシステムを作成する
system = System()
# システム(およびシステム内のすべてのモジュール)のクロック周波数を設定する
system.clk_domain = SrcClockDomain()
system.clk_domain.clock = "1GHz"
system.clk_domain.voltage_domain = VoltageDomain()
# システムをセットアップする
system.mem_mode = "timing"  # タイミングアクセスを使用する
system.mem_ranges = [AddrRange("512MB")]  # アドレス領域を設定する
# Simple CPUを作成する
# CPU毎に応じて`RiscvTimingSimpleCPU`, `ArmTimingSimpleCPU`を使用できる
system.cpu = X86TimingSimpleCPU()
# メモリバスを作成する。今回はシステムクロスバを使用する
system.membus = SystemXBar()
# CPUポートをメモリバスに接続する
system.cpu.icache_port = system.membus.cpu_side_ports
system.cpu.dcache_port = system.membus.cpu_side_ports
# CPUの割り込みコントローラをメモリバスに接続する
system.cpu.createInterruptController()
# X86にのみ、割り込みをメモリに接続する
# 注記: これらはメモリバスに直接接続され、キャッシュされない
# 他のISAでは以下の3行は削除すべきである
system.cpu.interrupts[0].pio = system.membus.mem_side_ports
system.cpu.interrupts[0].int_requestor = system.membus.cpu_side_ports
system.cpu.interrupts[0].int_responder = system.membus.mem_side_ports
# DDR3メモリコントローラを作成し、メモリバスに接続する
system.mem_ctrl = MemCtrl()
system.mem_ctrl.dram = DDR3_1600_8x8()
system.mem_ctrl.dram.range = system.mem_ranges[0]
system.mem_ctrl.port = system.membus.mem_side_ports
# システムポートをメモリバスに接続する
system.system_port = system.membus.cpu_side_ports
# X86の"hello world"バイナリを設定する。
# 他のISAではそれに応じたバイナリを設定する。
thispath = os.path.dirname(os.path.realpath(__file__))
binary = os.path.join(
    thispath,
    "../../../",
    "tests/test-progs/hello/bin/x86/linux/hello",
)
system.workload = SEWorkload.init_compatible(binary)
# シンプルな"Hello World"アプリケーションのプロセスを作成する
process = Process()
# コマンドを設定する
# cmdは実行バイナリ(およびその引数)で設定する
process.cmd = [binary]
# CPUにそのプロセスを使用するように設定し、スレッドコンテキストを作成する
system.cpu.workload = process
system.cpu.createThreads()
# root SimObjectを設定し、シミュレーションを開始する
root = Root(full_system=False, system=system)
# 上記で作成したオブジェクトをインスタンス化する
m5.instantiate()
print("Beginning simulation!")
exit_event = m5.simulate()
print("Exiting @ tick %i because %s" % (m5.curTick(), exit_event.getCause()))

msyksphinz.hatenablog.com