summaryrefslogtreecommitdiff
path: root/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/cache.c
blob: 024ba52ad8d6f24dcb78ef5521195702b7a02915 (plain)
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
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */

#include <metal/cache.h>
#include <metal/machine.h>

extern __inline__ void metal_cache_init(struct metal_cache *cache, int ways);
extern __inline__ int metal_cache_get_enabled_ways(struct metal_cache *cache);
extern __inline__ int metal_cache_set_enabled_ways(struct metal_cache *cache, int ways);

int metal_dcache_l1_available(int hartid) {
    switch (hartid) {
    case 0:
#ifdef __METAL_CPU_0_DCACHE_HANDLE
        return __METAL_CPU_0_DCACHE_HANDLE;
#endif  
        break;
    case 1:
#ifdef __METAL_CPU_1_DCACHE_HANDLE
        return __METAL_CPU_1_DCACHE_HANDLE;
#endif
        break;
    case 2:
#ifdef __METAL_CPU_2_DCACHE_HANDLE
        return __METAL_CPU_2_DCACHE_HANDLE;
#endif
        break;
    case 3:
#ifdef __METAL_CPU_3_DCACHE_HANDLE
        return __METAL_CPU_3_DCACHE_HANDLE;
#endif
        break;
    case 4:
#ifdef __METAL_CPU_4_DCACHE_HANDLE
        return __METAL_CPU_4_DCACHE_HANDLE;
#endif
        break;
    case 5:
#ifdef __METAL_CPU_5_DCACHE_HANDLE
        return __METAL_CPU_5_DCACHE_HANDLE;
#endif
        break;
    case 6:
#ifdef __METAL_CPU_6_DCACHE_HANDLE
        return __METAL_CPU_6_DCACHE_HANDLE;
#endif
        break;
    case 7:
#ifdef __METAL_CPU_7_DCACHE_HANDLE
        return __METAL_CPU_7_DCACHE_HANDLE;
#endif
        break;
    case 8:
#ifdef __METAL_CPU_8_DCACHE_HANDLE
        return __METAL_CPU_8_DCACHE_HANDLE;
#endif
        break;
    }
    return 0;
}

int metal_icache_l1_available(int hartid) {
    switch (hartid) {
    case 0:
#ifdef __METAL_CPU_0_ICACHE_HANDLE
        return __METAL_CPU_0_ICACHE_HANDLE;
#endif
        break;
    case 1:
#ifdef __METAL_CPU_1_ICACHE_HANDLE
        return __METAL_CPU_1_ICACHE_HANDLE;
#endif
        break;
    case 2:
#ifdef __METAL_CPU_2_ICACHE_HANDLE
        return __METAL_CPU_2_ICACHE_HANDLE;
#endif
        break;
    case 3:
#ifdef __METAL_CPU_3_ICACHE_HANDLE
        return __METAL_CPU_3_ICACHE_HANDLE;
#endif
        break;
    case 4:
#ifdef __METAL_CPU_4_ICACHE_HANDLE
        return __METAL_CPU_4_ICACHE_HANDLE;
#endif
        break;
    case 5:
#ifdef __METAL_CPU_5_ICACHE_HANDLE
        return __METAL_CPU_5_ICACHE_HANDLE;
#endif
        break;
    case 6:
#ifdef __METAL_CPU_6_ICACHE_HANDLE
        return __METAL_CPU_6_ICACHE_HANDLE;
#endif
        break;
    case 7:
#ifdef __METAL_CPU_7_ICACHE_HANDLE
        return __METAL_CPU_7_ICACHE_HANDLE;
#endif
        break;
    case 8:
#ifdef __METAL_CPU_8_ICACHE_HANDLE
        return __METAL_CPU_8_ICACHE_HANDLE;
#endif
        break;
    }
    return 0;
}

/*!
 * @brief CFlush.D.L1 instruction is a custom instruction implemented as a
 * state machine in L1 Data Cache (D$) with funct3=0, (for core with data caches)
 * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
 * 31     28 27    24 23    20 19     16 15   12 11     8 7      4 3      0
 * |--------|--------|--------|--------|--------|--------|--------|--------|
 * +-------------+------------+----------+------+--------+-----------------+
 * |sign immediate12b (simm12)|   rs1    | func3|    rd  |      opcode     |
 * |-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|
 * +--------------------------+----------+------+--------+-----------------+
 * 31     -0x40              20          15  0  12   x0  7      0x73       0
 * +--------+--------+--------+----------+------+--------+--------+--------+
 * where,
 * rs1 = 0x0, CFLUSH.D.L1 writes back and invalidates all lines in the L1 D$
 * rs1 != x0, CFLUSH.D.L1 writes back and invalidates the L1 D$ line containing
 *            the virtual address in integer register rs1.
 */
void metal_dcache_l1_flush(int hartid, uintptr_t address)
{
   if (metal_dcache_l1_available(hartid)) {
        // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
        __asm__ __volatile__ (".insn i 0x73, 0, x0, %0, -0x40" : : "r" (address));
        __asm__ __volatile__ ("fence.i");         // FENCE
    }
}

/*!
 * @brief CDiscard.D.L1 instruction is a custom instruction implemented as a
 * state machine in L1 Data Cache (D$) with funct3=0, (for core with data caches)
 * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
 * 31     28 27    24 23    20 19     16 15   12 11     8 7      4 3      0
 * |--------|--------|--------|--------|--------|--------|--------|--------|
 * +-------------+------------+----------+------+--------+-----------------+
 * |sign immediate12b (simm12)|   rs1    | func3|    rd  |      opcode     |
 * |-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|
 * +--------------------------+----------+------+--------+-----------------+
 * 31     -0x3E              20          15  0  12   x0  7      0x73       0
 * +--------+--------+--------+----------+------+--------+--------+--------+
 * where,
 * rs1 = 0x0, CDISCARD.D.L1 invalidates all lines in the L1 D$ with no writes back.
 * rs1 != x0, CDISCARD.D.L1 invalidates the L1 D$ line containing the virtual address
 *            in integer register rs1, with no writes back.
 */
void metal_dcache_l1_discard(int hartid, uintptr_t address)
{
   if (metal_dcache_l1_available(hartid)) {
        // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
        __asm__ __volatile__ (".insn i 0x73, 0, x0, %0, -0x3E" : : "r" (address));
        __asm__ __volatile__ ("fence.i");         // FENCE
    }
}

/*!
 * @brief CFlush.I.L1 instruction is a custom instruction implemented as a state
 * machine in L1 Instruction Cache (I$) with funct3=0, (for core with data caches)
 * It is an I type: .insn i opcode, func3, rd, rs1, simm12(signed immediate 12bs)
 * 31     28 27    24 23    20 19     16 15   12 11     8 7      4 3      0
 * |--------|--------|--------|--------|--------|--------|--------|--------|
 * +-------------+------------+----------+------+--------+-----------------+
 * |sign immediate12b (simm12)|   rs1    | func3|    rd  |      opcode     |
 * |-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|
 * +--------------------------+----------+------+--------+-----------------+
 * 31     -0x3F              20          15  0  12   x0  7      0x73       0
 * +--------+--------+--------+----------+------+--------+--------+--------+
 * CFLUSH.I.L1 invalidates all lines in the L1 I$.
 */
void metal_icache_l1_flush(int hartid)
{
   if (metal_icache_l1_available(hartid)) {
        // Using ‘.insn’ pseudo directive: '.insn i opcode, func3, rd, rs1, simm12'
        __asm__ __volatile__ (".insn i 0x73, 0, x0, x0, -0x3F" : : );
        __asm__ __volatile__ ("fence.i");         // FENCE
    }
}