1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
//! The system's address map and devices.
use super::defaults;
use crate::config::Console;
use serde::Deserialize;
/// System memory map and bus configuration.
///
/// Defines memory-mapped I/O base addresses, RAM configuration,
/// and system bus parameters.
#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SystemConfig {
/// UART MMIO base address
#[serde(default = "SystemConfig::default_uart_base")]
pub uart_base: u64,
/// virtio disk MMIO base address
#[serde(default = "SystemConfig::default_disk_base")]
pub disk_base: u64,
/// Main RAM base address
#[serde(default = "SystemConfig::default_ram_base")]
pub ram_base: u64,
/// CLINT (timer) MMIO base address
#[serde(default = "SystemConfig::default_clint_base")]
pub clint_base: u64,
/// Syscon (power control) MMIO base address
#[serde(default = "SystemConfig::default_syscon_base")]
pub syscon_base: u64,
/// Simulator control MMIO base address, which guest software writes
/// to reset or dump the stats and to end the run
#[serde(default = "SystemConfig::default_sim_control_base")]
pub sim_control_base: u64,
/// Kernel load offset from RAM base
#[serde(default = "SystemConfig::default_kernel_offset")]
pub kernel_offset: u64,
/// System bus width in bytes
#[serde(default = "SystemConfig::default_bus_width")]
pub bus_width: u64,
/// System bus latency in cycles
#[serde(default = "SystemConfig::default_bus_latency")]
pub bus_latency: u64,
/// CLINT timer divider (mtime increments every N cycles)
#[serde(default = "SystemConfig::default_clint_divider")]
pub clint_divider: u64,
/// Core clock in MHz.
#[serde(default = "SystemConfig::default_cpu_clock_mhz")]
pub cpu_clock_mhz: u64,
/// Wall-clock time the RTC reports at cycle zero, in seconds since the
/// Unix epoch.
#[serde(default = "SystemConfig::default_rtc_epoch_seconds")]
pub rtc_epoch_seconds: u64,
/// Where the UART console reads and writes.
#[serde(default)]
pub console: Console,
/// Time every device takes to answer a register access, in nanoseconds
/// (gem5's `pio_latency`).
#[serde(default = "SystemConfig::default_device_latency_ns")]
pub device_latency_ns: u64,
/// Per-device access latency in nanoseconds, by device name (`UART0`,
/// `CLINT`, `PLIC`, `VirtIO-Blk`, `SysCon`, `GoldfishRTC`, `HTIF`),
/// overriding `device_latency_ns`.
#[serde(default)]
pub device_latency_ns_overrides: std::collections::HashMap<String, u64>,
/// HTIF tohost address (0 = disabled). When non-zero, an HTIF device is
/// registered at this address to intercept riscv-tests pass/fail writes.
#[serde(default)]
pub tohost_addr: u64,
/// Number of harts in the simulated `SoC`. Default 1 (single-hart).
/// Multi-hart support lands later in Phase C; this knob exists from
/// Phase A so config plumbing is in place when n>1 is enabled.
#[serde(default = "SystemConfig::default_hart_count")]
pub hart_count: usize,
}
impl SystemConfig {
/// Returns the default UART MMIO base address.
const fn default_uart_base() -> u64 {
defaults::UART_BASE
}
/// Returns the default virtio disk MMIO base address.
const fn default_disk_base() -> u64 {
defaults::DISK_BASE
}
/// Returns the default RAM base address.
const fn default_ram_base() -> u64 {
defaults::RAM_BASE
}
/// Returns the default CLINT MMIO base address.
const fn default_clint_base() -> u64 {
defaults::CLINT_BASE
}
/// Returns the default system controller MMIO base address.
const fn default_syscon_base() -> u64 {
defaults::SYSCON_BASE
}
const fn default_sim_control_base() -> u64 {
defaults::SIM_CONTROL_BASE
}
/// Returns the default kernel load offset from RAM base.
const fn default_kernel_offset() -> u64 {
defaults::KERNEL_OFFSET
}
/// Returns the default system bus width in bytes.
const fn default_bus_width() -> u64 {
defaults::BUS_WIDTH
}
/// Returns the default system bus latency in cycles.
const fn default_bus_latency() -> u64 {
defaults::BUS_LATENCY
}
/// Returns the default CLINT timer divider value.
const fn default_clint_divider() -> u64 {
defaults::CLINT_DIVIDER
}
const fn default_cpu_clock_mhz() -> u64 {
defaults::CPU_CLOCK_MHZ
}
const fn default_device_latency_ns() -> u64 {
defaults::DEVICE_LATENCY_NS
}
/// Cycles a device takes to answer a register access unless overridden.
#[must_use]
pub const fn default_device_access_cycles(&self) -> u64 {
self.ns_to_cycles(self.device_latency_ns)
}
/// Cycles the device named `name` takes to answer a register access.
#[must_use]
pub fn device_access_cycles(&self, name: &str) -> u64 {
self.device_latency_ns_overrides
.get(name)
.map_or_else(|| self.default_device_access_cycles(), |&ns| self.ns_to_cycles(ns))
}
/// Core cycles in `ns` nanoseconds.
const fn ns_to_cycles(&self, ns: u64) -> u64 {
ns * self.cpu_clock_mhz / 1000
}
const fn default_rtc_epoch_seconds() -> u64 {
defaults::RTC_EPOCH_SECONDS
}
/// Returns the default hart count (1).
const fn default_hart_count() -> usize {
1
}
}
impl Default for SystemConfig {
fn default() -> Self {
Self {
uart_base: defaults::UART_BASE,
disk_base: defaults::DISK_BASE,
ram_base: defaults::RAM_BASE,
clint_base: defaults::CLINT_BASE,
syscon_base: defaults::SYSCON_BASE,
sim_control_base: defaults::SIM_CONTROL_BASE,
kernel_offset: defaults::KERNEL_OFFSET,
bus_width: defaults::BUS_WIDTH,
bus_latency: defaults::BUS_LATENCY,
clint_divider: defaults::CLINT_DIVIDER,
cpu_clock_mhz: defaults::CPU_CLOCK_MHZ,
rtc_epoch_seconds: defaults::RTC_EPOCH_SECONDS,
console: Console::default(),
device_latency_ns: defaults::DEVICE_LATENCY_NS,
device_latency_ns_overrides: std::collections::HashMap::new(),
tohost_addr: 0,
hart_count: 1,
}
}
}