---
# System prepended metadata

title: "Ramulator\_2.0 模擬器開發者導覽"
tags: [HBMPIM]

---


1. 整體模擬架構（CPU / Cache / Memory 模組互動流程）
2. 記憶體控制器內部架構（排程器、仲裁器、位址解碼、刷新單元）
3. 對應原始碼模組與檔案位置，方便後續開發與修改。
   完成後我會立即通知您。


# Ramulator 2.0 模擬器開發者導覽

## 整體模擬架構

*Ramulator 2.0 整體軟體架構示意圖：圖中展示了一個 DDR5 記憶體系統（含 RowHammer 緩解機制）的主要介面（深色方框）及其典型實作（淺色方框），以及各元件之間的交互流程*。Ramulator 2.0 採用**前端（CPU/Trace）**與**記憶體系統**分離的架構：前端產生記憶體請求，透過`send(mem_req)`介面送入記憶體系統；記憶體系統接收請求後，先經由\*\*位址對應模組（Address Mapper）**將記憶體位址解析為通道、排（Rank）、銀行（Bank）、列（Row）、欄（Column）等 DRAM 座標。完成位址轉換後，請求會放入**記憶體控制器（Memory Controller）\*\*的請求佇列中等待處理。記憶體控制器負責管理記憶體請求的排程、命令發送以及與 DRAM 裝置的互動。記憶體控制器每個時脈週期會執行以下步驟：

1. **刷新管理（Refresh Manager）**計時：控制器觸發刷新管理單元`tick()`，如到達刷新時間點則由刷新單元產生高優先權的維護請求（如`refresh`命令），並通過控制器的優先佇列插入等待執行。在典型 DDRx 系統中，刷新單元預設實作為**「全銀行刷新」（All-Bank Refresh）**，即發出一條命令刷新該 Rank 所有記憶體銀行。Ramulator 2.0 也支援其他刷新策略（例如逐銀行刷新），開發者可透過更換 RefreshManager 模組實作來模擬不同刷新機制。

2. **請求排程（Request Scheduling）**：控制器調用**排程器（Scheduler）**的`schedule_req()`方法，從請求佇列中選取下一個要服務的請求。Ramulator 2.0 預設的排程策略是 **FR-FCFS（First Ready, First Come First Serve）**，即優先選擇「已具備發出所需DRAM命令條件」且最早抵達的請求。排程器在決定服務哪一請求時，會考慮記憶體**列緩衝區命中**（Row hit）情況，以提高列緩衝重複使用率（FR-FCFS 正是透過優先已開啟列的請求來減少延遲）。如果需要實現其他排程政策（例如引入重新排序緩衝的演算法），可以透過新增不同的 Scheduler 實作類別來擴充（詳見後述）。

3. **DRAM 命令解碼與發行**：排程器選定請求後，會查詢\*\*DRAM 裝置模型（DRAM Device Model）\*\*以解碼對應的 DRAM 記憶體命令。例如，對於一個讀取請求，裝置模型可能回傳需要發出的命令（如`ACT`啟動列或`READ`讀取命令）。排程器取得建議命令後，控制器會檢查該命令是否符合 DRAM 定時約束（透過裝置模型的`check_ready(cmd)`介面檢查命令是否已滿足時序條件）。一旦確認可以發行，控制器即透過`issue_cmd(cmd)`將命令發送到 DRAM 裝置模型。**DRAM 裝置模型**會隨即更新其內部狀態和定時資訊（例如，記錄最近一次`ACT`/`READ`的時間，用於後續時序限制判斷）。Ramulator 2.0 的 DRAM 模型以階層式狀態機實現各種 DRAM 標準，並透過簡潔的人類可讀定義來描述不同命令的時序限制和作用。例如，DDR4/DDR5 等標準的規格參數已內建為預設值，使用者可在設定檔中以`timing: preset: DDR4_2400R`等方式載入。

4. **完成通知**：當某個記憶體請求被服務完畢（例如讀取資料已返回或寫入完成），記憶體控制器會執行該請求所註冊的完成回呼函式（`mem_req.callback()`）。這會通知前端處理器該記憶體操作已完成，從而讓處理器或 trace 模型繼續後續操作。若 Ramulator 2.0 以 **獨立模式** 執行，前端通常是一個簡單處理器模型或記憶體存取 trace parser；如果以 **庫模式** 與系統模擬器（如 gem5）整合，前端則由外部模擬器提供（例如 gem5 的 CPU + 快取階層），Ramulator 2.0 僅接收經快取未命中後送出的記憶體請求並模擬記憶體子系統。

整體而言，Ramulator 2.0 將 CPU 前端與記憶體系統解耦，並明確區分了各組件的介面與實作，使各模組間僅透過介面互動。上述流程中，紅色箭頭表示**記憶體請求路徑**，藍色箭頭表示**DRAM命令路徑**，綠色箭頭則表示**維護請求（如刷新）路徑**。透過模組化設計，Ramulator 2.0 的使用者可以方便地替換其中任一組件的實現，例如更換排程演算法或記憶體裝置類型，而無需修改其他模組的程式碼。

## 記憶體控制器架構

Ramulator 2.0 的**記憶體控制器**是內含多個子模組的複雜組件，負責協調記憶體請求從佇列到轉換為DRAM命令直至完成回報的全過程。其架構包含以下主要單元：

* **請求佇列（Request Queue）**：控制器內部維護一組請求佇列來暫存尚未服務的記憶體請求。典型實作會區分讀取與寫入請求的隊列，並可能設定各自的容量與門檻。例如，在預設 GenericController 中，讀寫請求可能分開緩衝，當寫入佇列累積過多時控制器可優先處理寫入以防止飽和。佇列實作與管理邏輯定義在控制器模組的原始碼中（如 `src/controller/controller.h` 中） 。

* **排程器（Scheduler）**：排程器決定從請求佇列中選出哪一個請求來發送對應的DRAM命令。Ramulator 2.0 將排程策略封裝為獨立介面 **IRequestScheduler**，並提供了多種具體實作。例如，`FRFCFS` 排程器實作位於 `src/scheduler/simple_scheduler.h`（假設檔名，內含 FR-FCFS 演算法）；若需要更換為其他排程策略，只需在設定檔中將 Scheduler 的 `impl` 屬性改為相應實作類別名稱。例如，可以定義並註冊一個 `ReorderScheduler` 來模擬具\*\*重新排序緩衝（Reorder Buffer）\*\*的排程策略，實現更積極的請求重新排序能力。排程器透過控制器提供的介面存取請求佇列，並可查詢 DRAM 裝置狀態以判斷命令是否可以發出。

* **仲裁器（Arbiter）**：仲裁器在某些情況下用於決定不同來源或類型請求的服務順序。例如，如果系統包含多個主體（如多核CPU）產生請求，共用同一記憶體控制器，仲裁器負責在不同來源之間公平或依優先級地分配記憶體頻寬。又或者，在控制器內部存在讀寫兩種佇列，仲裁器需要決策何時切換讀寫操作以維持效能和防止飢餓。Ramulator 2.0 中，如果使用簡單前端（單一來源）則不需特別仲裁；但在整合外部系統（如 gem5 多處理器）時，這部分策略通常由外部系統決定或可在 Ramulator 2.0 控制器中擴充實作。

* **位址解碼與映射（Address Mapping）**：位址映射模組在請求進入控制器前就已將物理位址轉譯為 DRAM 座標。然而，控制器需要知道所選請求的列是否已開啟、所在銀行是否閒置等資訊，這些都來自位址解析結果。因此位址映射的策略間接影響控制器行為。Ramulator 2.0 將映射策略封裝為 **IAddrMapper** 介面，典型預設為 `RoBaRaCoCh`（Row -> Bank -> Rank -> Column -> Channel 的位元排列）。如果要模擬不同的映射方式，如「Bank-Row-Col」順序，只需在設定檔中將 `AddrMapper: impl` 設為對應的類別（例如假設存在 `BaRoCoCh` 實作）。開發者也可新增自訂的地址映射類，在原始碼中新增檔案（例如 `src/memory_system/custom_mapper.h`）並繼承定義好的介面即可。

* **記憶體刷新單元（Refresh Manager）**：如前節所述，刷新單元負責按規定的刷新週期產生刷新命令。Ramulator 2.0 中刷新管理被抽象為 **IRefreshManager** 介面，預設實作為 `AllBankRefresh`（對應 JEDEC 標準的全銀行自刷新）。其原始碼定義可在 `src/controller/refresh_manager.h`（或類似路徑）中找到。若需要模擬其他刷新策略（例如 Fine-Grained Refresh 或 Per-Bank Refresh），可新增對應的實作類別，並在設定中將 RefreshManager 的 `impl` 指定為新類別名稱。

* **列開啟/關閉策略（Row Policy）**：DRAM 控制器在每次存取後可以選擇是否關閉（Precharge）開啟的列。Ramulator 2.0 提供 **IRowPolicy** 介面來抽象這一策略，預設實作為 **ClosedRowPolicy**，即每次存取完成後立即關閉該列（適合隨機存取降低行命中延遲）。另一常見策略是 **OpenRowPolicy**（開啟行策略），在預期同一列可能有後續存取時保持 row buffer 開啟，以提升行命中率。Ramulator 2.0 中可以透過更換 RowPolicy 模組來模擬不同策略，相關程式碼位於例如 `src/controller/row_policy.h`。在設定檔中，可將 `RowPolicy: impl` 設為 `OpenRowPolicy` 或其他自訂策略類別。

上述各模組透過控制器內部定義的介面進行協作。例如，排程器在每個週期被控制器呼叫以選擇請求，並可能透過裝置模型查詢當前命令可否發出；若選擇的是刷新請求則優先處理等。這種模組化設計讓記憶體控制器的功能更易於擴充和維護。開發者可以針對不同研究需求替換控制器的各部分組件，例如替換不同的 Scheduler、RefreshManager 或 RowPolicy，而不需要改動其他部分的代碼。

## 多種控制器與位址映射的配置與擴充

Ramulator 2.0 通過\*\*組態檔（YAML）\*\*來配置記憶體系統的各項參數與模組實現。使用者可以在組態中指定不同的控制器策略和位址映射方案，而無需修改程式碼。例如，以下是一段（假想的）Ramulator 2.0 設定片段，展示如何配置控制器的不同組件：

```yaml
MemorySystem:
  impl: GenericDRAM               # 記憶體系統實作類型
  DRAM:
    impl: DDR4                    # DRAM 規格（DDR4）
    org: preset: DDR4_8Gb_x8      # DRAM 組織預設參數
    timing: preset: DDR4_2400R    # DRAM 時序參數
  AddrMapper:
    impl: RoBaRaCoCh              # 位址映射：Row->Bank->Rank->Col->Channel
  Controller:
    impl: GenericController       # 記憶體控制器實作類型
    Scheduler:
      impl: FRFCFS                # 請求排程策略：FR-FCFS
      cap: 4                      # （例如）FR-FCFS 重新排序上限參數
    RefreshManager:
      impl: AllBank               # 刷新策略：全銀行刷新
    RowPolicy:
      impl: ClosedRowPolicy       # 列緩衝策略：每次存取後關閉
    # ...（如有需要可在此處列出其他插件或參數）...
```

上例展示了**FR-FCFS**與**Closed-row**策略的基線控制器配置。如果想切換為具\*\*重新排序緩衝（Reorder Buffer）\*\*的控制器實作，可採取以下兩種方式：

* **更換 Scheduler 策略**：如果重新排序僅影響排程演算法本身（例如允許更大範圍的 out-of-order 執行），可以透過提供新的 Scheduler 類別來實現。例如，可實作一個名為 `OutOfOrderScheduler` 的類別（繼承自 Scheduler 介面），在其中維護一個類似處理器 reorder buffer 的結構來允許請求更自由地重新排序。實作完成並註冊後，在設定檔中將 `Scheduler: impl` 改為 `OutOfOrderScheduler` 即可。控制器其餘部分（如控制流程、刷新機制）可繼續使用原有 GenericController 不變，但因 Scheduler 不同，行為上相當於一種新的控制器策略。

* **更換整個 Controller 實作**：若重新排序緩衝的引入涉及不只排程器，而是需要改變控制器內部對請求的管理方式（例如增加額外佇列或複雜的仲裁邏輯），則可以透過定義新的 **IController** 實作類別達成。例如創建 `ReorderBufferController` 類別（可參考 `src/controller/controller.h` 介面繼承實作），在其中自訂請求佇列結構和排程決策。同樣地，新類別定義好並在系統中註冊後，只需在 YAML 組態中將 Controller 的 `impl` 設為 `ReorderBufferController`。Ramulator 2.0 的工廠機制會自動載入此控制器類別，替換原本的 GenericController。

位址映射方面，Ramulator 2.0 預設提供如上所示的 **RoBaRaCoCh**（列→銀行→排→欄→通道）映射方式。若研究者想評估不同位址位元對應方案，例如 **Bank-Row-Col**（銀行位元在較高位，列位元次之）或更複雜的 XOR 映射，步驟與上述類似：

1. 在原始碼中新增一個繼承自 IAddrMapper 介面的實作類別，例如 `BankRowColMapper`，實作其位址轉換函式（將輸入地址位元排列為 BANK-ROW-COL 順序）。這個檔案可位於 `src/memory_system/bank_row_col_mapper.h`，並在實作中透過巨集或工廠註冊機制註冊類名「BankRowColMapper」。

2. 編譯更新後的 Ramulator 2.0，然後在 YAML 組態中將 `AddrMapper: impl` 改為 `BankRowColMapper`。重跑模擬即可使用新的位址映射。Ramulator 2.0 會自動辨識新介面實作並據此產生對應的記憶體系統配置。

值得注意的是，Ramulator 2.0 採用了**自我註冊的工廠模式**來管理這些介面與實作類別。也就是說，每當我們在程式中新增一個繼承介面的實作類，透過特定登錄機制（通常是在類的 cpp 檔案中呼叫工廠註冊函式或使用靜態初始化）註冊後，程式會將該類別與對應的介面關聯存入登錄表。之後，只要在組態檔的相應位置填入實作類的名稱，Ramulator 2.0 在啟動時就能自動地從工廠登錄表建立該實作物件並取代預設實作。這種做法免去了手動修改程式碼串接新模組的繁瑣步驟，極大地方便了模擬器的擴充。

總而言之，**FR-FCFS** 與 **Reorder Buffer** 代表了兩種不同的控制器請求排程理念：前者屬於**行緩衝優先**的漁翁式排程策略，而後者則允許更大範圍的請求重新排序以優化吞吐。Ramulator 2.0 透過高度模組化的架構，允許開發者以最小的代價在模擬中切換或實現這些策略。「**ROW-BANK-COL**」與「**BANK-ROW-COL**」則是地址位元分配順序的差異，會影響記憶體系統的空間區域性和並行度表現。使用 Ramulator 2.0，研究者可以輕鬆地在設定中調整這些參數並觀察其影響，而如果內建選項不敷所需，也能依上述步驟客製化新的控制器行為或位址映射方案。

## 主要邏輯模組與原始碼檔案對應

為方便開發者深入 Ramulator 2.0 的實作細節，下表列出本導覽中提及的主要邏輯模組及其對應的原始碼檔案位置：

* **Memory Controller（記憶體控制器）**：核心介面與基礎實作定義於 **`src/controller/controller.h`**。GenericController 及其衍生類（如 ReorderBufferController）也位於同一路徑下的 `.cpp` 實作檔案中。這些檔案包含控制器對請求佇列管理、與前端/裝置模型互動等邏輯。

* **Request Scheduler（請求排程器）**：位於 **`src/scheduler/`** 資料夾下，各種排程策略各有獨立檔案。例如，FR-FCFS 策略的實作在 *`simple_scheduler.h`*（名稱依 Ramulator 原始碼而定）中定義；如果有實作其他排程（如 `atlas_scheduler.h` 針對 ATLAS 演算法等），也會在此目錄下。對應的 `.cpp` 檔實現了 `schedule()` 等核心函式。

* **Address Mapper（位址映射模組）**：定義在 **`src/memory_system/address_mapper.h`** 以及對應的實作檔案中。此處包含 IAddrMapper 介面，以及 `RoBaRaCoCh` 等內建映射類別的定義。如果新增自訂映射類別（如 BankRowColMapper），則會新增檔案於此目錄下。

* **Refresh Manager（刷新管理單元）**：相關介面與實作位於 **`src/controller/refresh_manager.h`**（或可能的 `src/memory_system/refresh.h`）。AllBankRefresh 等策略的邏輯在對應 `.cpp` 實作中。Ramulator 1.0 將刷新策略實作在 Refresh.h 中；在 Ramulator 2.0，則經由介面類別細分，可在上述路徑中找到各策略類別。

* **Row Policy（列緩衝策略）**：其介面與實作可在 **`src/controller/row_policy.h`** 中查閱，包含 ClosedRowPolicy、OpenRowPolicy 等類別。這些類別的函式實作則通常在同名 `.cpp` 中實現。

* **Memory Device Models（記憶體裝置模型）**：各 DRAM 標準的模型定義散見於 **`src/dram/`** 或 **`src/memory_system/`** 目錄下。比如 DDR4、DDR5、HBM 等標準可能各有對應檔案（如 `ddr4.h/.cpp`）。這些檔案運用 Ramulator 2.0 提供的描述語法定義了 DRAM 的組織結構（banks, rows 等）以及時序參數和命令集合。

* **FrontEnd（前端處理器與核心）**：Ramulator 2.0 內建的簡易亂序核心和 trace 前端實作位於 **`src/frontend/`** 目錄內，例如 `trace_parser.h`、`ooocore.h` 等檔案。這部分模組產生並發出記憶體請求，透過 IFrontEnd 介面與記憶體系統溝通。在大多數記憶體系統研究中，此部分可視需要替換為更複雜的處理器模型或由外部模擬器提供。

以上檔案路徑及名稱對應於 Ramulator 2.0 專案的原始碼結構。在實際開發時，建議先閱讀 `README.md` 及相關說明文件以了解專案目錄佈局，再根據上述指引定位具體的檔案。Ramulator 2.0 的模組化設計使得各部分程式碼職責單一且集中。例如，想修改記憶體排程策略，只需專注於 `src/scheduler/` 下相關檔案而無須瀏覽整個專案。透過閱讀這些原始碼並結合本文前述的架構講解，開發者應能迅速上手在 Ramulator 2.0 上進行二次開發與實驗。各模組的實作細節和介面函式說明也可在程式碼註解和文獻中找到，鼓勵讀者深入參考以充分瞭解 Ramulator 2.0 的強大擴充能力與正確使用方法。

**參考來源：** 本文內容參考並整理自 Ramulator 2.0 論文以及 Ramulator 2.0 官方文件與原始碼。上述架構圖與技術細節摘錄自 Onur Mutlu 團隊發表的 Ramulator 2.0 論文及 GitHub 專案說明，以確保內容的正確性與權威性。希望本繁體中文開發者導覽能幫助您快速瞭解 Ramulator 2.0 模擬器的架構設計與模組實作，順利展開相關研究與開發工作！
