1 /* Copyright 2018 SiFive, Inc */
2 /* SPDX-License-Identifier: Apache-2.0 */
4 #include <metal/cache.h>
5 #include <metal/machine.h>
7 extern __inline__ void metal_cache_init(struct metal_cache *cache, int ways);
8 extern __inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache);
9 extern __inline__ int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways);
11 int metal_dcache_l1_available(int hartid) {
14 #ifdef __METAL_CPU_0_DCACHE_HANDLE
15 return __METAL_CPU_0_DCACHE_HANDLE;
19 #ifdef __METAL_CPU_1_DCACHE_HANDLE
20 return __METAL_CPU_1_DCACHE_HANDLE;
24 #ifdef __METAL_CPU_2_DCACHE_HANDLE
25 return __METAL_CPU_2_DCACHE_HANDLE;
29 #ifdef __METAL_CPU_3_DCACHE_HANDLE
30 return __METAL_CPU_3_DCACHE_HANDLE;
34 #ifdef __METAL_CPU_4_DCACHE_HANDLE
35 return __METAL_CPU_4_DCACHE_HANDLE;
39 #ifdef __METAL_CPU_5_DCACHE_HANDLE
40 return __METAL_CPU_5_DCACHE_HANDLE;
44 #ifdef __METAL_CPU_6_DCACHE_HANDLE
45 return __METAL_CPU_6_DCACHE_HANDLE;
49 #ifdef __METAL_CPU_7_DCACHE_HANDLE
50 return __METAL_CPU_7_DCACHE_HANDLE;
54 #ifdef __METAL_CPU_8_DCACHE_HANDLE
55 return __METAL_CPU_8_DCACHE_HANDLE;
62 int metal_icache_l1_available(int hartid) {
65 #ifdef __METAL_CPU_0_ICACHE_HANDLE
66 return __METAL_CPU_0_ICACHE_HANDLE;
70 #ifdef __METAL_CPU_1_ICACHE_HANDLE
71 return __METAL_CPU_1_ICACHE_HANDLE;
75 #ifdef __METAL_CPU_2_ICACHE_HANDLE
76 return __METAL_CPU_2_ICACHE_HANDLE;
80 #ifdef __METAL_CPU_3_ICACHE_HANDLE
81 return __METAL_CPU_3_ICACHE_HANDLE;
85 #ifdef __METAL_CPU_4_ICACHE_HANDLE
86 return __METAL_CPU_4_ICACHE_HANDLE;
90 #ifdef __METAL_CPU_5_ICACHE_HANDLE
91 return __METAL_CPU_5_ICACHE_HANDLE;
95 #ifdef __METAL_CPU_6_ICACHE_HANDLE
96 return __METAL_CPU_6_ICACHE_HANDLE;
100 #ifdef __METAL_CPU_7_ICACHE_HANDLE
101 return __METAL_CPU_7_ICACHE_HANDLE;
105 #ifdef __METAL_CPU_8_ICACHE_HANDLE
106 return __METAL_CPU_8_ICACHE_HANDLE;
114 * @brief CFlush.D.L1 instruction is a custom instruction implemented as a
115 * state machine in L1 Data Cache (D$) with funct3=0, (for core with data caches)
116 * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
117 * 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0
118 * |--------|--------|--------|--------|--------|--------|--------|--------|
119 * +-------------+------------+----------+------+--------+-----------------+
120 * |sign immediate12b (simm12)| rs1 | func3| rd | opcode |
121 * |-1-1-1-1 -1-1-0-0 -0-0-0-0|-x-x-x-x-x|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1|
122 * +--------------------------+----------+------+--------+-----------------+
123 * 31 -0x40 20 15 0 12 x0 7 0x73 0
124 * +--------+--------+--------+----------+------+--------+--------+--------+
126 * rs1 = 0x0, CFLUSH.D.L1 writes back and invalidates all lines in the L1 D$
127 * rs1 != x0, CFLUSH.D.L1 writes back and invalidates the L1 D$ line containing
128 * the virtual address in integer register rs1.
130 void metal_dcache_l1_flush(int hartid, uintptr_t address)
132 if (metal_dcache_l1_available(hartid)) {
133 // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
134 __asm__ __volatile__ (".insn i 0x73, 0, x0, %0, -0x40" : : "r" (address));
135 __asm__ __volatile__ ("fence.i"); // FENCE
140 * @brief CDiscard.D.L1 instruction is a custom instruction implemented as a
141 * state machine in L1 Data Cache (D$) with funct3=0, (for core with data caches)
142 * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
143 * 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0
144 * |--------|--------|--------|--------|--------|--------|--------|--------|
145 * +-------------+------------+----------+------+--------+-----------------+
146 * |sign immediate12b (simm12)| rs1 | func3| rd | opcode |
147 * |-1-1-1-1 -1-1-0-0 -0-0-0-0|-x-x-x-x-x|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1|
148 * +--------------------------+----------+------+--------+-----------------+
149 * 31 -0x3E 20 15 0 12 x0 7 0x73 0
150 * +--------+--------+--------+----------+------+--------+--------+--------+
152 * rs1 = 0x0, CDISCARD.D.L1 invalidates all lines in the L1 D$ with no writes back.
153 * rs1 != x0, CDISCARD.D.L1 invalidates the L1 D$ line containing the virtual address
154 * in integer register rs1, with no writes back.
156 void metal_dcache_l1_discard(int hartid, uintptr_t address)
158 if (metal_dcache_l1_available(hartid)) {
159 // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
160 __asm__ __volatile__ (".insn i 0x73, 0, x0, %0, -0x3E" : : "r" (address));
161 __asm__ __volatile__ ("fence.i"); // FENCE
166 * @brief CFlush.I.L1 instruction is a custom instruction implemented as a state
167 * machine in L1 Instruction Cache (I$) with funct3=0, (for core with data caches)
168 * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
169 * 31 28 27 24 23 20 19 16 15 12 11 8 7 4 3 0
170 * |--------|--------|--------|--------|--------|--------|--------|--------|
171 * +-------------+------------+----------+------+--------+-----------------+
172 * |sign immediate12b (simm12)| rs1 | func3| rd | opcode |
173 * |-1-1-1-1 -1-1-0-0 -0-0-0-0|-0-0-0-0-0|0-0-0-|-0-0-0-0|-0-1-1-1 -0-0-1-1|
174 * +--------------------------+----------+------+--------+-----------------+
175 * 31 -0x3F 20 15 0 12 x0 7 0x73 0
176 * +--------+--------+--------+----------+------+--------+--------+--------+
177 * CFLUSH.I.L1 invalidates all lines in the L1 I$.
179 void metal_icache_l1_flush(int hartid)
181 if (metal_icache_l1_available(hartid)) {
182 // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
183 __asm__ __volatile__ (".insn i 0x73, 0, x0, x0, -0x3F" : : );
184 __asm__ __volatile__ ("fence.i"); // FENCE