Skip to content

Commit e6b0add

Browse files
committed
Replace CLINT with preliminary ACLINT support
Based on the implementation of CLINT, a preliminary ACLINT is implemented, including the basic logic for operating `mtimer`, `mswi`, and `sswi`. CLINT was replaced with ACLINT, and the old CLINT implementation was removed entirely. Currently, due to the lack of implementation, the introduced ACLINT uses only supervisor-level IPI. Therefore, although the logic for mswi is implemented, it is not being used at the moment. The implementation can be tested by `make check SMP=n`, where n is the number of harts you want to simulate.
1 parent 59d39f5 commit e6b0add

File tree

7 files changed

+355
-143
lines changed

7 files changed

+355
-143
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ OBJS := \
5353
plic.o \
5454
uart.o \
5555
main.o \
56-
clint.o \
56+
aclint.o \
5757
$(OBJS_EXTRA)
5858

5959
deps := $(OBJS:%.o=.%.o.d)

aclint.c

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
#include <stdint.h>
2+
#include "device.h"
3+
#include "riscv.h"
4+
#include "riscv_private.h"
5+
6+
/* ACLINT MTIMER */
7+
void aclint_mtimer_update_interrupts(hart_t *hart, mtimer_state_t *mtimer)
8+
{
9+
if (semu_timer_get(&mtimer->mtime) >= mtimer->mtimecmp[hart->mhartid])
10+
hart->sip |= RV_INT_STI_BIT; // Set Supervisor Timer Interrupt
11+
else
12+
hart->sip &= ~RV_INT_STI_BIT; // Clear Supervisor Timer Interrupt
13+
}
14+
15+
static bool aclint_mtimer_reg_read(mtimer_state_t *mtimer,
16+
uint32_t addr,
17+
uint32_t *value)
18+
{
19+
/**
20+
* @brief `addr & 0x4` is used to determine the upper or lower 32 bits
21+
* of the mtimecmp register. If `addr & 0x4` is 0, then the lower 32
22+
* bits are accessed.
23+
*
24+
* `addr >> 3` is used to get the index of the mtimecmp array. In
25+
* "ACLINT MTIMER Compare Register Map", each mtimecmp register is 8
26+
* bytes long. So, we need to divide the address by 8 to get the index.
27+
*
28+
*/
29+
30+
/* mtimecmp (0x4300000 ~ 0x4307FF8) */
31+
if (addr < 0x7FF8) {
32+
*value =
33+
(uint32_t) (mtimer->mtimecmp[addr >> 3] >> (addr & 0x4 ? 32 : 0));
34+
return true;
35+
}
36+
37+
/* mtime (0x4307FF8 ~ 0x4308000) */
38+
if (addr < 0x8000) {
39+
*value = (uint32_t) (semu_timer_get(&mtimer->mtime) >>
40+
(addr & 0x4 ? 32 : 0));
41+
return true;
42+
}
43+
return false;
44+
}
45+
46+
static bool aclint_mtimer_reg_write(mtimer_state_t *mtimer,
47+
uint32_t addr,
48+
uint32_t value)
49+
{
50+
/**
51+
* @brief The `cmp_val & 0xFFFFFFFF` is used to select the upper 32 bits
52+
* of mtimer->mtimecmp[addr >> 3], then shift the value to the left by
53+
* 32 bits to set the upper 32 bits.
54+
*
55+
*/
56+
57+
/* mtimecmp (0x4300000 ~ 0x4307FF8) */
58+
if (addr < 0x7FF8) {
59+
uint64_t cmp_val = mtimer->mtimecmp[addr >> 3];
60+
61+
if (addr & 0x4)
62+
cmp_val = (cmp_val & 0xFFFFFFFF) | ((uint64_t) value << 32);
63+
else
64+
cmp_val = (cmp_val & 0xFFFFFFFF00000000ULL) | value;
65+
66+
mtimer->mtimecmp[addr >> 3] = cmp_val;
67+
return true;
68+
}
69+
70+
/* mtime (0x4307FF8 ~ 0x4308000) */
71+
if (addr < 0x8000) {
72+
uint64_t mtime_val = mtimer->mtime.begin;
73+
if (addr & 0x4)
74+
mtime_val = (mtime_val & 0xFFFFFFFF) | ((uint64_t) value << 32);
75+
else
76+
mtime_val = (mtime_val & 0xFFFFFFFF00000000ULL) | value;
77+
78+
semu_timer_rebase(&mtimer->mtime, mtime_val);
79+
return true;
80+
}
81+
82+
return false;
83+
}
84+
85+
void aclint_mtimer_read(hart_t *hart,
86+
mtimer_state_t *mtimer,
87+
uint32_t addr,
88+
uint8_t width,
89+
uint32_t *value)
90+
{
91+
if (!aclint_mtimer_reg_read(mtimer, addr, value))
92+
vm_set_exception(hart, RV_EXC_LOAD_FAULT, hart->exc_val);
93+
94+
*value >>= (RV_MEM_SW - width);
95+
}
96+
97+
void aclint_mtimer_write(hart_t *hart,
98+
mtimer_state_t *mtimer,
99+
uint32_t addr,
100+
uint8_t width,
101+
uint32_t value)
102+
{
103+
if (!aclint_mtimer_reg_write(mtimer, addr, value << (RV_MEM_SW - width)))
104+
vm_set_exception(hart, RV_EXC_STORE_FAULT, hart->exc_val);
105+
}
106+
107+
/* ACLINT MSWI */
108+
void aclint_mswi_update_interrupts(hart_t *hart, mswi_state_t *mswi)
109+
{
110+
if (mswi->msip[hart->mhartid])
111+
hart->sip |= RV_INT_SSI_BIT; // Set Machine Software Interrupt
112+
else
113+
hart->sip &= ~RV_INT_SSI_BIT; // Clear Machine Software Interrupt
114+
}
115+
116+
static bool aclint_mswi_reg_read(mswi_state_t *mswi,
117+
uint32_t addr,
118+
uint32_t *value)
119+
{
120+
/**
121+
* @brief `msip` is an array where each entry corresponds to a Hart,
122+
* each entry is 4 bytes (32 bits). So, we need to divide the address
123+
* by 4 to get the index.
124+
*/
125+
126+
/* Address range for msip: 0x4400000 ~ 0x4404000 */
127+
if (addr < 0x4000) {
128+
*value = mswi->msip[addr >> 2];
129+
return true;
130+
}
131+
return false;
132+
}
133+
134+
static bool aclint_mswi_reg_write(mswi_state_t *mswi,
135+
uint32_t addr,
136+
uint32_t value)
137+
{
138+
if (addr < 0x4000) {
139+
mswi->msip[addr >> 2] = value & 0x1; // Only the LSB is valid
140+
return true;
141+
}
142+
return false;
143+
}
144+
145+
void aclint_mswi_read(hart_t *hart,
146+
mswi_state_t *mswi,
147+
uint32_t addr,
148+
uint8_t width,
149+
uint32_t *value)
150+
{
151+
if (!aclint_mswi_reg_read(mswi, addr, value))
152+
vm_set_exception(hart, RV_EXC_LOAD_FAULT, hart->exc_val);
153+
154+
*value >>= (RV_MEM_SW - width);
155+
}
156+
157+
void aclint_mswi_write(hart_t *hart,
158+
mswi_state_t *mswi,
159+
uint32_t addr,
160+
uint8_t width,
161+
uint32_t value)
162+
{
163+
if (!aclint_mswi_reg_write(mswi, addr, value << (RV_MEM_SW - width)))
164+
vm_set_exception(hart, RV_EXC_STORE_FAULT, hart->exc_val);
165+
}
166+
167+
/* ACLINT SSWI */
168+
void aclint_sswi_update_interrupts(hart_t *hart, sswi_state_t *sswi)
169+
{
170+
if (sswi->ssip[hart->mhartid])
171+
hart->sip |= RV_INT_SSI_BIT; // Set Supervisor Software Interrupt
172+
else
173+
hart->sip &= ~RV_INT_SSI_BIT; // Clear Supervisor Software Interrupt
174+
}
175+
176+
static bool aclint_sswi_reg_read(__attribute__((unused)) sswi_state_t *sswi,
177+
uint32_t addr,
178+
uint32_t *value)
179+
{
180+
/* Address range for ssip: 0x4500000 ~ 0x4504000 */
181+
if (addr < 0x4000) {
182+
*value = 0; // Upper 31 bits are zero, and LSB reads as 0
183+
return true;
184+
}
185+
return false;
186+
}
187+
188+
static bool aclint_sswi_reg_write(sswi_state_t *sswi,
189+
uint32_t addr,
190+
uint32_t value)
191+
{
192+
if (addr < 0x4000) {
193+
sswi->ssip[addr >> 2] = value & 0x1; // Only the LSB is valid
194+
195+
return true;
196+
}
197+
return false;
198+
}
199+
200+
void aclint_sswi_read(hart_t *hart,
201+
sswi_state_t *sswi,
202+
uint32_t addr,
203+
uint8_t width,
204+
uint32_t *value)
205+
{
206+
if (!aclint_sswi_reg_read(sswi, addr, value))
207+
vm_set_exception(hart, RV_EXC_LOAD_FAULT, hart->exc_val);
208+
209+
*value >>= (RV_MEM_SW - width);
210+
}
211+
212+
void aclint_sswi_write(hart_t *hart,
213+
sswi_state_t *sswi,
214+
uint32_t addr,
215+
uint8_t width,
216+
uint32_t value)
217+
{
218+
if (!aclint_sswi_reg_write(sswi, addr, value << (RV_MEM_SW - width)))
219+
vm_set_exception(hart, RV_EXC_STORE_FAULT, hart->exc_val);
220+
}

clint.c

Lines changed: 0 additions & 96 deletions
This file was deleted.

0 commit comments

Comments
 (0)