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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
//! # hisi-hal — Hardware Abstraction Layer for HiSilicon WS63 (RISC-V).
//!
//! A comprehensive HAL providing safe, idiomatic Rust APIs for all WS63
//! peripherals. Modeled on esp-hal patterns with typed GPIO drivers, audited
//! clock metadata, typed identities, and embedded-hal trait implementations.
//!
//! ## Clock gating
//!
//! Most peripherals need their CLDO_CRG clock gate enabled before register
//! access. The gates default to enabled out of reset; `clock_init::init_clocks()`
//! sets up the system clocks for firmware that does not boot through flashboot.
//! Constructors like `I2c::new_i2c0()`, `Uart::new_uart0()`, and `Watchdog::new()`
//! write configuration registers immediately. WDT/RTC/TCXO are always-on.
//!
//! ```ignore
//! // Illustrative shape only (`system`/`peripherals` stand in for your tokens):
//! let clocks = clock_init::init_clocks(&system.sys_ctl0, &system.cldo_crg);
//! // Now safe to construct peripheral drivers
//! let uart = Uart::new_uart0(peripherals.UART0, Config::default());
//! ```
//!
//! ## MSRV
//!
//! The minimum supported Rust version is **1.88** (declared as `rust-version` in
//! `Cargo.toml` — bumped from 1.85 for the `instability` crate). An MSRV bump is a
//! minor-version change, not a patch.
// `no_std` for firmware builds; `std` is linked under `cfg(test)` ONLY on the
// host so the lib unit tests can use the standard test harness (run via
// `cargo test --target x86_64`). On the RISC-V target the lib stays `no_std`
// even under the `test` cfg: `cargo test --target riscv32imfc-...` builds the
// lib-test target too (alongside tests/hil.rs), and `std`/`test` don't exist on
// the bare-metal target — the host-only unit-test modules are themselves gated
// `#[cfg(all(test, not(target_arch = "riscv32")))]`, so they vanish there.
// 0.5.0: every public item is documented; `deny` so a future undocumented pub item
// fails the build (and the doc CI job) rather than silently regressing.
// docs.rs-only nightly features for the `#[instability::unstable]` "requires unstable"
// markers (the `doc(cfg(feature="unstable"))` annotations). Only active under
// `--cfg docsrs` (set by docs.rs); stable builds are unaffected. Mirrors esp-hal.
// Exactly one chip must be selected (each pulls its PAC + soc/<chip>.rs). There is
// NO default chip (esp-hal style) — every consumer names one explicitly.
compile_error!;
compile_error!;
compile_error!;
// ── Internal helper macros (must come before any `unstable_module!` use) ────
// Crate-local `unstable_module!`/`unstable_driver!` + the `#[macro_export]`'d
// `any_peripheral!`/`infallible!`. Private module — the gating macros are NOT
// `#[macro_export]` (esp-hal pattern: crate-internal helpers), and `#[macro_use]`
// makes them visible crate-wide from this point on. The two `#[macro_export]`
// macros still land at the crate root for downstream use regardless.
// ── Chip-neutral core (compiles for every chip) ────────────────────────────
unstable_module!
/// GPIO drivers: type-erased `AnyPin`, typed `Input`/`Output`/`Flex`.
/// Interrupt controller access and IRQ enable/handler registration.
/// Peripheral singleton tokens and the `Peripherals` struct (`take()`/`steal()`).
/// Common re-exports for `use hisi_hal::prelude::*;`.
// Sealed marker traits restricting external trait implementations.
/// SoC-specific constants and PAC aliases for the selected chip.
unstable_module!
/// TCXO always-on clock/counter driver.
/// Time/frequency newtypes (`Hertz`, durations) used across the HAL.
/// General-purpose hardware timer driver.
/// UART serial driver (blocking and `embedded-io`).
// ── WS63-specific / not-yet-ported-to-BS21 drivers ──────────────────────────
// Gated to chip-ws63 for now: they touch WS63-only peripherals (Wi-Fi/RF, the
// full crypto block, SFC) or WS63-specific CRG/clock registers. BS21 ports land
// in later milestones; gating keeps the BS21 build to the milestone-1 subset
// while leaving the WS63 build (the default) byte-identical.
unstable_driver!
// D-cache maintenance (custom HiSilicon CSRs). WS63-only: the cache CSR layout is
// core-specific and tied to the still-unstable DMA/cache-line ownership contract.
unstable_module!
/// Clock and reset generator metadata: audited peripheral clock-gate bits.
unstable_module!
// DMA: the register block + the mem-to-mem path are chip-neutral (Dma0 uses the
// chip-neutral PAC base). Peripheral-paced flow control (DmaPeripheral request IDs)
// is chip-ws63-only within the module; BS2X gets mem-to-mem.
unstable_module!
/// eFuse one-time-programmable memory access.
// Chip-neutral: the embassy-time driver reads TCXO_HZ/TIMER_CLOCK_HZ and the
// alarm interrupt from `soc::chip`, and the TCXO/TIMER register blocks are
// register-identical across WS63 and BS2X (verified vs fbb_ws63 / fbb_bs2x).
unstable_driver!
// I2C is a DIFFERENT IP per chip: WS63 has a custom v150 core (i2c.rs), BS2X has a
// Synopsys DesignWare v151 core (i2c_v151.rs). Both are exposed as `hal::i2c`; the
// register blocks come from each chip's PAC (the BS2X v151 layout was rewritten
// into BS2X.svd / bs2x-pac for this).
/// I2C driver (WS63 custom v150 core).
unstable_module!
/// I2S audio interface driver.
/// Pin mux / pad I/O configuration helpers.
unstable_module!
/// Low-speed ADC (v154) driver.
// BS2X 13-bit ADC (v153) — chip-bs21-only (WS63's ADC is the different `lsadc`
// v154). bs2x-pac has the correct `gadc` register block; the driver reaches the
// ANA/PMU power sub-blocks (not in the PAC) via raw addresses. See gadc.rs.
unstable_module!
// BS2X-only HID peripherals (no WS63 analogue): key-matrix scanner + quadrature
// decoder. bs2x-pac has faithful register blocks; see keyscan.rs / qdec.rs.
unstable_module!
// BS2X PDM-mic audio front-end (v150) — config-level (the PCM data path is DMA-fed).
unstable_module!
// BS2X USB 2.0 OTG (Synopsys DWC OTG) — config-level (core-ID; full stack deferred).
unstable_module!
unstable_module!
unstable_module!
// BS2X-enabled shared drivers (`pwm`, `spi`, `wdt`, `ulp_gpio`). These are not
// per-module soft-gated, but the whole `chip-bs21` target is hard-gated by
// `unstable` above until BS2X silicon HIL exists. They build for BS2X because
// (a) the driver code is chip-neutral (it goes through `crate::soc::pac` aliases),
// (b) their peripheral instances are in both `Peripherals` structs, and (c) BS2X
// uses the SAME IP version as WS63 — PWM v151, SPI v151, WDT v151 (the fbb_bs2x
// vs fbb_ws63 `*_regs_def.h` headers are byte-identical bar copyright comments),
// and `ulp_gpio` reuses the GPIO v150 block that regular `gpio` already drives on
// BS2X (blinky). So the register layout is verified, not guessed. What's guaranteed
// today is a register-correct, compiling blocking API.
//
// Still chip-ws63-only (different IP version or no BS2X peripheral): i2c (v150 vs
// BS2X v151), rtc (v100 vs v150), lsadc (v154 vs v153), i2s/sfc (no BS2X instance),
// and the clock/crypto/system stack (deeper port).
/// PWM driver (v151) with typed `PwmPeriod`/`Duty` config.
// RTC is a different IP per chip: WS63 v100 (rtc.rs), BS2X v150 (rtc_v150.rs, a
// 64-bit counter with a coherent-read handshake). Both exposed as `hal::rtc`.
unstable_module!
unstable_module!
unstable_module!
unstable_driver!
unstable_module!
unstable_module!
/// SPI driver (v151), blocking and `embedded-hal`.
/// System control block access and the `System` token.
unstable_module!
// TRNG differs per chip: WS63 (trng.rs) vs BS2X v1 (trng_v1.rs). Both `hal::trng`.
/// True random number generator driver (WS63).
unstable_module!
/// On-chip temperature sensor driver.
unstable_module!
/// Watchdog timer driver (v151).
/// Re-export of the peripheral singleton token struct.
pub use Peripherals;
/// Re-export of the system control token.
pub use System;