Skip to content

Commit

Permalink
fix(aia): external interrupt priority from CLINT or IMSIC
Browse files Browse the repository at this point in the history
* The current external interrupts come from two sources, CLINT and IMSIC.
  The external interrupt priority number of CLINT is 0, and the external interrupt priority number of IMSIC is 1~2047.
  We use the global variable external_interrupt_select to determine the source of the external interrupt.
  If the external interrupt comes from CLINT, external_interrupt_select = false;
  if the external interrupt comes from IMSIC, external_interrupt_select = true.

* The case where the priority number is greater than 255 is added to the interrupt priority comparison method.

* The priority number of each interrupt in the iprios array occupies 8 bits, and its read data is masked by the corresponding bit of the xie register,
  so when writing the xie register, the read data of the iprios array needs to be updated.
  • Loading branch information
sinceforYy committed Jan 22, 2025
1 parent ca3a869 commit 3869753
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 66 deletions.
1 change: 1 addition & 0 deletions include/isa.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ void isa_update_mtopi();
void isa_update_stopi();
void isa_update_vstopi();
void isa_update_hgeip();
void isa_update_external_interrupt_select();
#endif
void isa_sync_custom_mflushpwr(bool l2FlushDone);

Expand Down
4 changes: 4 additions & 0 deletions src/cpu/difftest/ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ void difftest_non_reg_interrupt_pending(void *nonRegInterruptPending) {
memcpy(&cpu.non_reg_interrupt_pending, nonRegInterruptPending, sizeof(struct NonRegInterruptPending));
isa_update_mip(cpu.non_reg_interrupt_pending.lcofi_req);
#ifdef CONFIG_RV_IMSIC
if (cpu.non_reg_interrupt_pending.platform_irp_meip || cpu.non_reg_interrupt_pending.from_aia_meip ||
cpu.non_reg_interrupt_pending.platform_irp_seip || cpu.non_reg_interrupt_pending.from_aia_seip) {
isa_update_external_interrupt_select();
}
isa_update_mtopi();
isa_update_stopi();
isa_update_vstopi();
Expand Down
8 changes: 8 additions & 0 deletions src/isa/riscv64/difftest/ref.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,14 @@ void isa_update_mhpmcounter_overflow(uint64_t mhpmeventOverflowVec) {
}

#ifdef CONFIG_RV_IMSIC
void isa_update_external_interrupt_select() {
if (cpu.non_reg_interrupt_pending.from_aia_meip || cpu.non_reg_interrupt_pending.from_aia_seip) {
cpu.external_interrupt_select = true;
} else {
cpu.external_interrupt_select = false;
}
}

void isa_update_mtopi() {
update_mtopi();
}
Expand Down
7 changes: 5 additions & 2 deletions src/isa/riscv64/include/isa-def.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ struct NonRegInterruptPending {
bool platform_irp_stip;
bool platform_irp_vseip;
bool platform_irp_vstip;
bool from_aia_meip;
bool from_aia_seip;
bool lcofi_req;
};

Expand Down Expand Up @@ -82,7 +84,6 @@ struct MemEventQueryResult {
typedef struct TriggerModule TriggerModule;
typedef struct IpriosModule IpriosModule;
typedef struct IpriosSort IpriosSort;
typedef struct HighestPrioIntr HighestPrioIntr;

typedef struct {
// Below will be synced by regcpy when run difftest, DO NOT TOUCH
Expand Down Expand Up @@ -187,12 +188,14 @@ typedef struct {
#ifdef CONFIG_RV_IMSIC
struct FromAIA fromaia;
IpriosModule* MIprios;
IpriosModule* MIprios_rdata;
IpriosModule* SIprios;
IpriosModule* SIprios_rdata;
IpriosModule* VSIprios;
IpriosSort* MIpriosSort;
IpriosSort* SIpriosSort;
IpriosSort* VSIpriosSort;
HighestPrioIntr* HighestPrioIntr;
bool external_interrupt_select;
#endif

} riscv64_CPU_state;
Expand Down
9 changes: 3 additions & 6 deletions src/isa/riscv64/local-include/aia.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,11 @@ typedef struct IpriosModule {

typedef struct {
bool enable;
bool isZero;
bool greaterThan255;
uint8_t priority;
} IpriosEnable;

typedef struct HighestPrioIntr {
uint8_t idx;
uint8_t priority;
} HighestPrioIntr;

typedef struct IpriosSort {
IpriosEnable ipriosEnable[IPRIO_ENABLE_NUM];
} IpriosSort;
Expand All @@ -38,7 +35,7 @@ typedef struct {
} Hviprios;

bool iprio_is_zero(IpriosModule* iprios);
void set_iprios_sort(uint64_t topi_gather, IpriosSort* iprios_sort, IpriosModule* iprios);
void set_iprios_sort(uint64_t topi_gather, IpriosSort* iprios_sort, IpriosModule* iprios, uint8_t xei, mtopei_t* xtopei);
void set_viprios_sort(uint64_t topi_gather);
uint8_t high_iprio(IpriosSort* ipriosSort, uint8_t xei);
uint8_t get_prio_idx_in_group(uint8_t irq);
Expand Down
101 changes: 65 additions & 36 deletions src/isa/riscv64/system/aia.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,23 @@ bool intr_enable(uint64_t topi_gather, uint64_t idx) {
return (topi_gather >> interrupt_default_prio[idx]) & 0x1;
}

void set_iprios_sort(uint64_t topi_gather, IpriosSort* iprios_sort, IpriosModule* iprios) {
void set_iprios_sort(uint64_t topi_gather, IpriosSort* iprios_sort, IpriosModule* iprios, uint8_t xei, mtopei_t* xtopei) {
for (int i = 0; i < IPRIO_ENABLE_NUM; i++) {
if (intr_enable(topi_gather, i)) {
iprios_sort->ipriosEnable[i].enable = true;
iprios_sort->ipriosEnable[i].priority = (iprios->iprios[interrupt_default_prio[i]/8].val >> (8 * (interrupt_default_prio[i]%8))) & 0xff;
if (interrupt_default_prio[i] == xei) {
iprios_sort->ipriosEnable[i].isZero = !cpu.external_interrupt_select;
iprios_sort->ipriosEnable[i].greaterThan255 = xtopei->iprio > 255;
iprios_sort->ipriosEnable[i].priority = xtopei->iprio & 0xff;
} else {
iprios_sort->ipriosEnable[i].isZero = ((iprios->iprios[interrupt_default_prio[i]/8].val >> (8 * (interrupt_default_prio[i]%8))) & 0xff) == 0;
iprios_sort->ipriosEnable[i].greaterThan255 = false;
iprios_sort->ipriosEnable[i].priority = (iprios->iprios[interrupt_default_prio[i]/8].val >> (8 * (interrupt_default_prio[i]%8))) & 0xff;
}
} else {
iprios_sort->ipriosEnable[i].enable = false;
iprios_sort->ipriosEnable[i].isZero = false;
iprios_sort->ipriosEnable[i].greaterThan255 = false;
iprios_sort->ipriosEnable[i].priority = 0;
}
}
Expand All @@ -72,7 +82,7 @@ void set_iprios_sort(uint64_t topi_gather, IpriosSort* iprios_sort, IpriosModule
void handle_irq_hviprio(uint8_t irq, uint64_t topi, uint8_t priority) {
word_t idx = get_prio_idx_in_group(irq);
if (intr_enable(topi, idx)) {
cpu.VSIpriosSort->ipriosEnable[idx].enable = true;
cpu.VSIpriosSort->ipriosEnable[idx].isZero = priority == 0;
cpu.VSIpriosSort->ipriosEnable[idx].priority = priority;
}
}
Expand All @@ -93,6 +103,15 @@ void set_hviprios(Hviprios hprios) {
}

void set_viprios_sort(uint64_t topi_gather) {
for (int i = 0; i < IPRIO_ENABLE_NUM; i++) {
if (intr_enable(topi_gather, i)) {
cpu.VSIpriosSort->ipriosEnable[i].enable = true;
cpu.VSIpriosSort->ipriosEnable[i].isZero = true;
} else {
cpu.VSIpriosSort->ipriosEnable[i].enable = false;
}
}

Hviprios hviprios;
for (int i = 0; i < 24; i++) {
hviprios.hviprios[i] = 0;
Expand All @@ -105,47 +124,57 @@ void set_viprios_sort(uint64_t topi_gather) {
}

uint8_t high_iprio(IpriosSort* ipriosSort, uint8_t xei) {
uint8_t high_prio_idx = cpu.HighestPrioIntr->idx;
uint8_t high_prio_idx = 0;

for (int i = 1; i < IPRIO_ENABLE_NUM; i ++) {
// enable
bool left_enable = ipriosSort->ipriosEnable[high_prio_idx].enable;
bool right_enable = ipriosSort->ipriosEnable[i].enable;

bool left_disenable = !left_enable;

uint8_t left_priority = ipriosSort->ipriosEnable[high_prio_idx].priority;
uint8_t right_priority = ipriosSort->ipriosEnable[i].priority;

bool left_priority_is_zero = left_priority == 0;
bool right_priority_is_zero = right_priority == 0;

bool left_priority_is_not_zero = !left_priority_is_zero;
bool right_priority_is_not_zero = !right_priority_is_zero;

bool left_leq_xei = high_prio_idx <= get_prio_idx_in_group(xei);
bool right_leq_xei = i <= get_prio_idx_in_group(xei);

bool left_great_xei = !left_leq_xei;

bool left_leq_right = left_priority <= right_priority;
bool left_great_right = !left_leq_right;

if (left_disenable && right_enable) {
// zero
bool left_prio_is_zero = ipriosSort->ipriosEnable[high_prio_idx].isZero;
bool right_prio_is_zero = ipriosSort->ipriosEnable[i].isZero;

bool left_prio_is_not_zero = !left_prio_is_zero;
bool right_prio_is_not_zero = !right_prio_is_zero;

// idx
bool left_idx_leq_xei = high_prio_idx <= get_prio_idx_in_group(xei);
bool right_idx_leq_xei = i <= get_prio_idx_in_group(xei);

bool left_idx_greater_xei = !left_idx_leq_xei;

// greater than 255
bool left_prio_greater_255 = ipriosSort->ipriosEnable[high_prio_idx].greaterThan255;
bool right_prio_greater_255 = ipriosSort->ipriosEnable[i].greaterThan255;

bool left_prio_leq_255 = !left_prio_greater_255;
bool right_prio_leq_255 = !right_prio_greater_255;

// priority
uint8_t left_prio = ipriosSort->ipriosEnable[high_prio_idx].priority;
uint8_t right_prio = ipriosSort->ipriosEnable[i].priority;

bool left_prio_leq_right_prio = left_prio <= right_prio;
bool left_prio_greater_right_prio = !left_prio_leq_right_prio;

if ((left_disenable && right_enable) ||
(left_enable && right_enable &&
(
(left_prio_is_zero && right_prio_is_not_zero && left_idx_greater_xei) ||
(left_prio_is_not_zero && right_prio_is_zero && right_idx_leq_xei) ||
(left_prio_is_not_zero && right_prio_is_not_zero &&
(
(left_prio_greater_255 && right_prio_leq_255) ||
(left_prio_leq_255 && right_prio_leq_255 && left_prio_greater_right_prio)
)
)
)
)
) {
high_prio_idx = i;
} else if (left_enable && right_enable) {
if (left_priority_is_zero && right_priority_is_not_zero) {
if (left_great_xei || right_leq_xei) {
high_prio_idx = i;
}
} else if (left_priority_is_not_zero && right_priority_is_zero) {
if (left_great_xei && right_leq_xei) {
high_prio_idx = i;
}
} else if (left_priority_is_not_zero && right_priority_is_not_zero) {
if (left_great_right) {
high_prio_idx = i;
}
}
}
}

Expand Down
Loading

0 comments on commit 3869753

Please sign in to comment.