andes_riscv/
l1c.rs

1//! L1C, level 1 cache
2
3use cctl_cmds::L1D_VA_LOCK;
4
5use crate::register;
6use crate::riscv;
7
8// cctl_cmd
9pub mod cctl_cmds {
10    pub const L1D_VA_INVAL: u8 = 0;
11    pub const L1D_VA_WB: u8 = 1;
12    pub const L1D_VA_WBINVAL: u8 = 2;
13    pub const L1D_VA_LOCK: u8 = 3;
14    pub const L1D_VA_UNLOCK: u8 = 4;
15    pub const L1D_WBINVAL_ALL: u8 = 6;
16    pub const L1D_WB_ALL: u8 = 7;
17
18    pub const L1I_VA_INVAL: u8 = 8;
19    pub const L1I_VA_LOCK: u8 = 11;
20    pub const L1I_VA_UNLOCK: u8 = 12;
21
22    pub const L1D_IX_INVAL: u8 = 16;
23    pub const L1D_IX_WB: u8 = 17;
24    pub const L1D_IX_WBINVAL: u8 = 18;
25
26    pub const L1D_IX_RTAG: u8 = 19;
27    pub const L1D_IX_RDATA: u8 = 20;
28    pub const L1D_IX_WTAG: u8 = 21;
29    pub const L1D_IX_WDATA: u8 = 22;
30
31    pub const L1D_INVAL_ALL: u8 = 23;
32
33    pub const L1I_IX_INVAL: u8 = 24;
34    pub const L1I_IX_RTAG: u8 = 27;
35    pub const L1I_IX_RDATA: u8 = 28;
36    pub const L1I_IX_WTAG: u8 = 29;
37    pub const L1I_IX_WDATA: u8 = 30;
38}
39
40#[inline(always)]
41pub fn dc_is_enabled() -> bool {
42    register::mcache_ctl().read().dc_en()
43}
44
45#[inline(always)]
46pub fn ic_is_enabled() -> bool {
47    register::mcache_ctl().read().ic_en()
48}
49
50#[inline(always)]
51pub unsafe fn dc_enable() {
52    if !dc_is_enabled() {
53        register::mcache_ctl().modify(|w| w.set_dc_warnd(0b11));
54        register::mcache_ctl().modify(|w| {
55            // TODO: set dc_warnd
56            w.set_dpref_en(true);
57            w.set_dc_en(true);
58        });
59    }
60}
61
62#[inline(always)]
63pub unsafe fn dc_disable() {
64    if dc_is_enabled() {
65        register::mcache_ctl().modify(|w| w.set_dc_en(false));
66    }
67}
68
69#[inline(always)]
70pub unsafe fn ic_enable() {
71    if !ic_is_enabled() {
72        register::mcache_ctl().modify(|w| {
73            w.set_ic_en(true);
74            w.set_ipref_en(true);
75            w.set_cctl_suen(true);
76        });
77    }
78}
79
80#[inline(always)]
81pub unsafe fn ic_disable() {
82    if ic_is_enabled() {
83        register::mcache_ctl().modify(|w| w.set_ic_en(false));
84    }
85}
86
87#[inline(always)]
88pub unsafe fn dc_invalidate_all() {
89    register::mcctlcommand().write_value(cctl_cmds::L1D_INVAL_ALL as u32);
90}
91
92#[inline(always)]
93pub unsafe fn dc_writeback_all() {
94    register::mcctlcommand().write_value(cctl_cmds::L1D_WB_ALL as u32);
95}
96
97#[inline(always)]
98pub unsafe fn dc_flush_all() {
99    register::mcctlcommand().write_value(cctl_cmds::L1D_WBINVAL_ALL as u32);
100}
101
102#[inline(always)]
103fn cctl_get_address() -> u32 {
104    register::mcctlbeginaddr().read()
105}
106
107// HPM_L1C_CACHELINE_SIZE
108fn cacheline_size() -> u32 {
109    let dsz = register::mdcm_cfg().read().dsz();
110    match dsz {
111        0 => 0,
112        1 => 8,
113        2 => 16,
114        3 => 32,
115        4 => 64,
116        5 => 128,
117        _ => 0,
118    }
119}
120
121pub unsafe fn l1c_op(opcode: u8, address: u32, size: u32) {
122    let mstatus = riscv::register::mstatus::read();
123    if mstatus.mie() {
124        riscv::register::mstatus::clear_mie();
125    }
126
127    let ver = register::mmsc_cfg().read().vcctl();
128
129    if ver != 0 {
130        register::mcctlbeginaddr().write_value(address);
131        let mut next_address = address;
132
133        while next_address < address + size && next_address >= address {
134            register::mcctlcommand().write_value(opcode as u32);
135            next_address = cctl_get_address();
136        }
137    } else {
138        let cl_size = cacheline_size();
139        if cl_size == 0 {
140            return;
141        }
142        let mut i = 0;
143        while i < size {
144            register::mcctlbeginaddr().write_value(address + i);
145            register::mcctlcommand().write_value(opcode as u32);
146            i += cl_size;
147        }
148    }
149
150    if mstatus.mie() {
151        riscv::register::mstatus::set_mie();
152    }
153}
154
155fn check_addr_size(address: u32, size: u32) {
156    let cl_sz = cacheline_size();
157
158    assert!(
159        address % cl_sz == 0,
160        "address must be aligned to cacheline size"
161    );
162    assert!(size % cl_sz == 0, "size must be multiple of cacheline size");
163}
164
165pub unsafe fn dc_fill_lock(address: u32, size: u32) {
166    check_addr_size(address, size);
167    l1c_op(L1D_VA_LOCK, address, size);
168}
169
170pub unsafe fn dc_invalidate(address: u32, size: u32) {
171    check_addr_size(address, size);
172    l1c_op(cctl_cmds::L1D_VA_INVAL, address, size);
173}
174
175pub unsafe fn dc_writeback(address: u32, size: u32) {
176    check_addr_size(address, size);
177    l1c_op(cctl_cmds::L1D_VA_WB, address, size);
178}
179
180pub unsafe fn dc_flush(address: u32, size: u32) {
181    check_addr_size(address, size);
182    l1c_op(cctl_cmds::L1D_VA_WBINVAL, address, size);
183}
184
185pub unsafe fn ic_invalidate(address: u32, size: u32) {
186    check_addr_size(address, size);
187    l1c_op(cctl_cmds::L1I_VA_INVAL, address, size);
188}
189
190pub unsafe fn ic_fill_lock(address: u32, size: u32) {
191    check_addr_size(address, size);
192    l1c_op(cctl_cmds::L1I_VA_LOCK, address, size);
193}
194
195#[inline]
196pub fn cacheline_align_down(addr: u32) -> u32 {
197    addr & !(cacheline_size() - 1)
198}
199
200#[inline]
201pub fn cacheline_align_up(addr: u32) -> u32 {
202    cacheline_align_down(addr + cacheline_size() - 1)
203}