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
//! WS63 D-cache maintenance via the HiSilicon custom RISC-V CSRs.
//!
//! The WS63 core has a **4 KB, 32-byte-line, non-coherent** data cache (enabled
//! at boot). A DMA / bus master sees physical RAM directly, so software must keep
//! the cache and RAM in sync around a transfer:
//!
//! * **Before** a master *reads* CPU-written data — [`clean_range`] (write the
//! dirty cache lines back to RAM) so the master sees the new bytes.
//! * **After** a master *writes* memory, before the CPU reads it —
//! [`invalidate_range`] (drop the stale cache lines) so the CPU re-fetches from
//! RAM instead of returning the old cached value.
//!
//! Cache control uses two custom CSRs (mirroring the vendor LiteOS
//! `arch/riscv/include/arch/cache.h` + `osal_dcache_*`):
//! `DCINCVA` (`0x7C5`, the target address) and `DCMAINT` (`0x7C3`, the command,
//! whose bits are `VA = 0x1` "by virtual address", `DCIV = 0x4` "invalidate",
//! `DCC = 0x8` "clean"). The vendor `hal_dma_v151_enable()` flushes the whole
//! D-cache before kicking a transfer; these by-range ops are the finer-grained
//! equivalent.
//!
//! All ops are no-ops on a non-riscv (host) build so the crate's host unit tests
//! still compile.
/// D-cache line size, in bytes (WS63: 32).
pub const CACHE_LINE: usize = 32;
unsafe
unsafe
/// Clean (write back) `[addr, addr + len)` from the D-cache to memory.
///
/// Call **before** a DMA / bus master reads memory the CPU has written, so the
/// master sees the current data rather than stale RAM.
///
/// # Safety
/// `addr`/`len` must describe a real mapped range; the op affects whole 32-byte
/// cache lines covering the range.
pub unsafe
/// Invalidate `[addr, addr + len)` in the D-cache (drop the cached copy).
///
/// Call **after** a DMA / bus master writes memory, before the CPU reads it, so
/// the CPU re-fetches from RAM. Invalidation discards whole cache lines, so the
/// range should be 32-byte ([`CACHE_LINE`]) aligned — otherwise a partial line
/// shared with neighbouring *dirty* data would lose that neighbour's writes. Use
/// [`flush_range`] if the range may hold dirty data you need to keep.
///
/// # Safety
/// As [`clean_range`]; additionally the caller must accept that any cached writes
/// to the covered lines are discarded.
pub unsafe
/// Clean **and** invalidate `[addr, addr + len)` (a full flush) by address.
///
/// # Safety
/// As [`clean_range`].
pub unsafe
/// Clean and invalidate the entire D-cache.
///
/// This matches the vendor LiteOS `ArchDCacheFlush()` operation. Prefer the
/// range operations when ownership is limited to a known buffer; this function
/// exists for vendor ABI shims that explicitly request a whole-cache flush.
///
/// # Safety
///
/// The caller must ensure that globally flushing the D-cache cannot race with
/// another execution context that owns cacheable memory.
pub unsafe