Skip to content

Commit 4020bff

Browse files
committed
Preliminary ACLINT implementation
In this commit, based on the implementation of CLINT, an preliminary ACLINT is implemented, including the basic logic for operating `mtimer`, `mswi`, and `sswi`. Additionally, introduces a new script `gen-hart-dts.py` for generating device-tree configurations and renames the original script to `gen-clint-dts.py`. The new script is currently unused. A new macro SEMU_FEATURE_ACLINT is also added to feature.h, allowing the replacement of CLINT with ACLINT in the implementation. 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. You can test it directly using the command `make check SMP=n`, where n is the number of harts you want to simulate.
1 parent 59d39f5 commit 4020bff

File tree

8 files changed

+467
-12
lines changed

8 files changed

+467
-12
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+
}

device.h

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,59 @@ void virtio_blk_write(hart_t *vm,
172172
uint32_t *virtio_blk_init(virtio_blk_state_t *vblk, char *disk_file);
173173
#endif /* SEMU_HAS(VIRTIOBLK) */
174174

175+
#if SEMU_HAS(ACLINT)
176+
/* ACLINT MTIMER */
177+
typedef struct {
178+
uint64_t mtimecmp[4095]; // Machine Timer Compare array
179+
semu_timer_t mtime; // Machine Timer Counter
180+
} mtimer_state_t;
181+
182+
void aclint_mtimer_update_interrupts(hart_t *hart, mtimer_state_t *mtimer);
183+
void aclint_mtimer_read(hart_t *hart,
184+
mtimer_state_t *mtimer,
185+
uint32_t addr,
186+
uint8_t width,
187+
uint32_t *value);
188+
void aclint_mtimer_write(hart_t *hart,
189+
mtimer_state_t *mtimer,
190+
uint32_t addr,
191+
uint8_t width,
192+
uint32_t value);
193+
194+
/* ACLINT MSWI */
195+
typedef struct {
196+
uint32_t msip[4096]; // Machine Software Interrupt Pending array
197+
} mswi_state_t;
198+
199+
void aclint_mswi_update_interrupts(hart_t *hart, mswi_state_t *mswi);
200+
void aclint_mswi_read(hart_t *hart,
201+
mswi_state_t *mswi,
202+
uint32_t addr,
203+
uint8_t width,
204+
uint32_t *value);
205+
void aclint_mswi_write(hart_t *hart,
206+
mswi_state_t *mswi,
207+
uint32_t addr,
208+
uint8_t width,
209+
uint32_t value);
210+
211+
/* ACLINT SSWI */
212+
typedef struct {
213+
uint32_t ssip[4096]; // Supervisor Software Interrupt Pending array
214+
} sswi_state_t;
215+
216+
void aclint_sswi_update_interrupts(hart_t *hart, sswi_state_t *sswi);
217+
void aclint_sswi_read(hart_t *hart,
218+
sswi_state_t *sswi,
219+
uint32_t addr,
220+
uint8_t width,
221+
uint32_t *value);
222+
void aclint_sswi_write(hart_t *hart,
223+
sswi_state_t *sswi,
224+
uint32_t addr,
225+
uint8_t width,
226+
uint32_t value);
227+
#else
175228
/* clint */
176229
typedef struct {
177230
uint32_t msip[4096];
@@ -190,9 +243,9 @@ void clint_write(hart_t *vm,
190243
uint32_t addr,
191244
uint8_t width,
192245
uint32_t value);
246+
#endif
193247

194248
/* memory mapping */
195-
196249
typedef struct {
197250
bool stopped;
198251
uint32_t *ram;
@@ -205,5 +258,12 @@ typedef struct {
205258
#if SEMU_HAS(VIRTIOBLK)
206259
virtio_blk_state_t vblk;
207260
#endif
261+
#if SEMU_HAS(ACLINT)
262+
/* ACLINT */
263+
mtimer_state_t mtimer;
264+
mswi_state_t mswi;
265+
sswi_state_t sswi;
266+
#else
208267
clint_state_t clint;
268+
#endif
209269
} emu_state_t;

feature.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,10 @@
1212
#define SEMU_FEATURE_VIRTIONET 1
1313
#endif
1414

15+
/* ACLINT */
16+
#ifndef SEMU_FEATURE_ACLINT
17+
#define SEMU_FEATURE_ACLINT 1
18+
#endif
19+
1520
/* Feature test macro */
1621
#define SEMU_HAS(x) SEMU_FEATURE_##x

0 commit comments

Comments
 (0)