3030#define SET_BIT (reg , bit ) do { (reg) |= BIT(bit); } while(0)
3131
3232
33- static void esp32c3_do_int (ESP32C3IntMatrixState * s , int line )
34- {
35- qemu_irq_pulse (s -> out_irqs [line ]);
36- }
37-
38-
3933static int esp32c3_get_output_line_level (ESP32C3IntMatrixState * s , int line )
4034{
4135 int level_shared = 0 ;
@@ -51,27 +45,37 @@ static int esp32c3_get_output_line_level(ESP32C3IntMatrixState *s, int line)
5145 return level_shared ;
5246}
5347
54- /**
55- * Try to clear the given interrupt from the pending bitmap.
56- * If the signal is shared with other interrupt sources, make sure all of them are low (0)
57- * before clearing the pending IRQ from the bitmap.
58- */
59- static void esp32c3_intmatrix_clear_pending (ESP32C3IntMatrixState * s , int line )
48+ static bool esp32c3_intmatrix_line_should_assert (ESP32C3IntMatrixState * s , int line )
6049{
61- /* Check if another GPIO IRQ is sharing the same output line. They must all be low before
62- * clearing the pending bit. This is due to the fact that output lines
63- * can be shared on the ESP32-C3 */
64- const int output_level = esp32c3_get_output_line_level (s , line );
65- if (!output_level ) {
66- /* The output interrupt line is 0, so we can clear the pending flag */
67- CLEAR_BIT (s -> irq_pending , line );
50+ if (line == 0 ) {
51+ return false;
6852 }
53+
54+ return BIT_SET (s -> irq_enabled , line ) &&
55+ esp32c3_get_output_line_level (s , line ) != 0 &&
56+ (s -> irq_prio [line ] >= s -> irq_thres );
6957}
7058
59+ static void esp32c3_intmatrix_update_line (ESP32C3IntMatrixState * s , int line )
60+ {
61+ if (line == 0 ) {
62+ return ;
63+ }
7164
72- static inline bool esp32c3_intmatrix_can_trigger (ESP32C3IntMatrixState * s )
65+ const bool assert_line = esp32c3_intmatrix_line_should_assert (s , line );
66+
67+ if (assert_line ) {
68+ qemu_irq_raise (s -> out_irqs [line ]);
69+ } else {
70+ qemu_irq_lower (s -> out_irqs [line ]);
71+ }
72+ }
73+
74+ static void esp32c3_intmatrix_refresh_all (ESP32C3IntMatrixState * s )
7375{
74- return esp_cpu_accept_interrupts (s -> cpu );
76+ for (uint32_t i = 1 ; i <= ESP32C3_CPU_INT_COUNT ; i ++ ) {
77+ esp32c3_intmatrix_update_line (s , i );
78+ }
7579}
7680
7781
@@ -80,7 +84,7 @@ static void esp32c3_intmatrix_irq_handler(void *opaque, int n, int level)
8084 ESP32C3IntMatrixState * s = ESP32C3_INTMATRIX (opaque );
8185
8286 /* Update the level mirror */
83- assert (n <= ESP32C3_INT_MATRIX_INPUTS );
87+ assert (n < ESP32C3_INT_MATRIX_INPUTS );
8488
8589 /* Make sure level is 0 or 1 */
8690 level = level ? 1 : 0 ;
@@ -94,128 +98,13 @@ static void esp32c3_intmatrix_irq_handler(void *opaque, int n, int level)
9498 CLEAR_BIT (s -> irq_levels , n );
9599 }
96100
97- const int line = s -> irq_map [n ];
98-
99- /* If the line is not enable, don't do anything special, the level has been recorded already.
100- * Don't do anything if the line is at the same level as before */
101- if ((s -> irq_enabled & BIT (line )) == 0 || former_level == level ) {
102- return ;
103- }
104-
105- /* If the new level is high, check that the priority is equal or bigger than the threshold.
106- * If that's the case, we can execute the interrupt, else, mark it as pending. */
107- if (level == 1 ) {
108- #if INTMATRIX_DEBUG
109- info_report ("\x1b[31m[INTMATRIX] IRQ %d priority set to %d, CPU threshold %d \x1b[0m\n" ,
110- line , s -> irq_prio [line ], s -> irq_thres );
111- #endif
112-
113- if (s -> irq_prio [line ] >= s -> irq_thres && esp32c3_intmatrix_can_trigger (s )) {
114- esp32c3_do_int (s , line );
115- } else {
116- SET_BIT (s -> irq_pending , line );
117- }
118- } else if (BIT_SET (s -> irq_pending , line )) {
119- esp32c3_intmatrix_clear_pending (s , line );
120- }
121- }
122-
123-
124- static void esp32c3_intmatrix_irq_prio_changed (ESP32C3IntMatrixState * s , uint32_t line , uint8_t priority )
125- {
126- const bool accept = esp32c3_intmatrix_can_trigger (s );
127-
128- if (accept && priority >= s -> irq_thres && BIT_SET (s -> irq_pending , line )) {
129- /* No need to clear the pending bit here. As soon as the interrupt source will be ACK by the
130- * software, its level will be update, as well as its pending state. */
131- esp32c3_do_int (s , line );
132- }
133- }
134-
135-
136- static void esp32c3_intmatrix_core_prio_changed (ESP32C3IntMatrixState * s , uint64_t new_cpu_priority )
137- {
138- uint64_t pending = s -> irq_pending ;
139- const bool accept = esp32c3_intmatrix_can_trigger (s );
140-
141- if (pending && accept ) {
142- int64_t priority = -1 ;
143- uint_fast32_t line = 0 ;
144-
145- /* Clear all the interrupts that have a lower priority than the new CPU threshold */
146- for (uint_fast32_t i = 1 ; i <= ESP32C3_CPU_INT_COUNT ; i ++ ) {
147-
148- const uint64_t line_prio = s -> irq_prio [i ];
149- if (line_prio < new_cpu_priority ) {
150- CLEAR_BIT (pending , i );
151- }
152- }
153-
154- /* No high level interrupt pending? */
155- if (pending == 0 ) {
156- return ;
157- }
158-
159- /* Look for the highest priority pending interrupt */
160- for (uint_fast32_t i = 1 ; i <= ESP32C3_CPU_INT_COUNT ; i ++ ) {
161- const int64_t line_prio = (int64_t ) s -> irq_prio [i ];
162- if (BIT_SET (pending , i ) && line_prio > priority ) {
163- priority = line_prio ;
164- line = i ;
165- }
166- }
167-
168- /* Make sure a line was selected with its new priority */
169- assert (line != 0 );
170- assert (priority >= new_cpu_priority );
171- /* No need to clear the pending bit here. As soon as the interrupt source will be ACK by the
172- * software, its level will be update, as well as its pending state. */
173- esp32c3_do_int (s , line );
174- }
175- }
176-
177-
178- /**
179- * This function is called when the status (enabled/disabled) of a line has just been changed.
180- * It will update the pending IRQ map.
181- */
182- static void esp32c3_intmatrix_irq_status_changed (ESP32C3IntMatrixState * s , uint32_t line , int enabled )
183- {
184- const bool accept = esp32c3_intmatrix_can_trigger (s );
185-
186- if (!enabled ) {
187-
188- /* IRQ has just been disabled, if any interrupt is pending, clear it */
189- CLEAR_BIT (s -> irq_pending , line );
190-
191- } else if (esp32c3_get_output_line_level (s , line )) {
192-
193- /* IRQ has just been re-enabled, we have to check if any interrupt source is mapped to it, and
194- * if that's the case, check if their level is high, as we would need to potentially trigger an
195- * interrupt. */
196- SET_BIT (s -> irq_pending , line );
197-
198- if (accept ) {
199- /* If the CPU can accept interrupt, trigger an interrupt now */
200- esp32c3_do_int (s , line );
201- }
101+ /* Nothing to do if the level is unchanged. */
102+ if (former_level != level ) {
103+ const int line = s -> irq_map [n ];
104+ esp32c3_intmatrix_update_line (s , line );
202105 }
203106}
204107
205-
206- /**
207- * Callback invoked by the CPU as soon as interrupts are re-enabled
208- */
209- static bool esp32c3_intmatrix_mie_enabled (void * opaque )
210- {
211- ESP32C3IntMatrixState * s = ESP32C3_INTMATRIX (opaque );
212- /* We need to check if any interrupt is pending and trigger it. We have such function already, triggered when
213- * the core priority changes, let's reuse this function by giving the same core priority */
214- esp32c3_intmatrix_core_prio_changed (s , s -> irq_thres );
215- return s -> irq_pending != 0 ;
216- }
217-
218-
219108static uint64_t esp32c3_intmatrix_read (void * opaque , hwaddr addr , unsigned int size )
220109{
221110 ESP32C3IntMatrixState * s = ESP32C3_INTMATRIX (opaque );
@@ -251,11 +140,16 @@ static void esp32c3_intmatrix_write(void* opaque, hwaddr addr, uint64_t value, u
251140 const uint32_t index = addr / sizeof (uint32_t );
252141
253142 if (index < ESP32C3_INT_MATRIX_INPUTS ) {
254-
255- s -> irq_map [index ] = (value & 0x1f );
143+ const uint8_t old_line = s -> irq_map [index ];
144+ const uint8_t new_line = (value & 0x1f );
145+ s -> irq_map [index ] = new_line ;
256146#if INTMATRIX_DEBUG
257147 info_report ("\x1b[31m[INTMATRIX] Mapping interrupt %d to CPU line %d\x1b[0m\n" , index , s -> irq_map [index ]);
258148#endif
149+ if (old_line != new_line ) {
150+ esp32c3_intmatrix_update_line (s , old_line );
151+ esp32c3_intmatrix_update_line (s , new_line );
152+ }
259153
260154 } else if (index >= ESP32C3_INTMATRIX_IO_PRIO_START && index < ESP32C3_INTMATRIX_IO_PRIO_END ) {
261155
@@ -266,7 +160,7 @@ static void esp32c3_intmatrix_write(void* opaque, hwaddr addr, uint64_t value, u
266160 info_report ("\x1b[31m[INTMATRIX] Priority of line %d set to %d\x1b[0m\n" , line , priority );
267161#endif
268162 /* Check if the new priority interrupts the CPU */
269- esp32c3_intmatrix_irq_prio_changed (s , line , priority );
163+ esp32c3_intmatrix_update_line (s , line );
270164
271165 } else if (index == ESP32C3_INTMATRIX_IO_THRESH_REG ) {
272166
@@ -289,7 +183,7 @@ static void esp32c3_intmatrix_write(void* opaque, hwaddr addr, uint64_t value, u
289183#if INTMATRIX_DEBUG
290184 info_report ("\x1b[31m[INTMATRIX] Setting CPU IRQ threshold to %d\x1b[0m" , priority );
291185#endif
292- esp32c3_intmatrix_core_prio_changed ( s , priority );
186+ esp32c3_intmatrix_refresh_all ( s );
293187 }
294188
295189 } else if (index == ESP32C3_INTMATRIX_IO_ENABLE_REG ) {
@@ -302,7 +196,7 @@ static void esp32c3_intmatrix_write(void* opaque, hwaddr addr, uint64_t value, u
302196 const int new_st = value & BIT (i );
303197 const int old_st = prev & BIT (i );
304198 if (new_st != old_st ) {
305- esp32c3_intmatrix_irq_status_changed (s , i , new_st ? 1 : 0 );
199+ esp32c3_intmatrix_update_line (s , i );
306200 }
307201 }
308202 } else if (index == ESP32C3_INTMATRIX_IO_TYPE_REG ) {
@@ -334,7 +228,6 @@ static void esp32c3_intmatrix_reset_hold(Object *obj, ResetType type)
334228 memset (s -> irq_map , 0 , sizeof (s -> irq_map ));
335229 memset (s -> irq_prio , 0 , sizeof (s -> irq_prio ));
336230 s -> irq_thres = 0 ;
337- s -> irq_pending = 0 ;
338231 s -> irq_levels = 0 ;
339232 s -> irq_trigger = 0 ;
340233 s -> irq_enabled = 0 ;
@@ -349,15 +242,7 @@ static void esp32c3_intmatrix_reset_hold(Object *obj, ResetType type)
349242
350243static void esp32c3_intmatrix_realize (DeviceState * dev , Error * * errp )
351244{
352- ESP32C3IntMatrixState * s = ESP32C3_INTMATRIX (dev );
353- EspRISCVCPU * cpu = s -> cpu ;
354- EspRISCVCPUClass * cpu_klass = ESP_CPU_GET_CLASS (cpu );
355-
356245 esp32c3_intmatrix_reset_hold (OBJECT (dev ), RESET_TYPE_COLD );
357-
358- /* Register MIE callback */
359- assert (cpu );
360- cpu_klass -> esp_cpu_register_mie_callback (cpu , esp32c3_intmatrix_mie_enabled , s );
361246}
362247
363248
0 commit comments