[Milkymist-devel] QEMU/LM32

Fabrice Bellard fabrice at bellard.org
Thu Mar 4 15:19:46 PST 2010


Michael Walle wrote:
> Hi Fabrice,
> 
> thanks for your reply.
> 
> Am Thursday 04 March 2010 18:54:06 schrieb Fabrice Bellard:
>> Hi,
>>> A few points need to be sorted out before the merge is done:
>>> - Michael is unsure about the interrupt handling. Esp. if it is
>>> possible to manipulate env->interrupt_request within a translation block.
>>> Could you check that?
>> The following code in the PIC is almost surely incorrect:
>>
>>      if ((env->ie & IE_IE) && (env->ip & env->im))
>>          cpu_interrupt(env, CPU_INTERRUPT_HARD);
>>
>> CPU_INTERRUPT_HARD means that a hardware interrupt is pending. When it
>> is set, QEMU will exit the current translated block as soon as possible.
>> You should not test the CPU irq masking state before setting it
>> otherwise the CPU will miss interrupts.
>>
>> The code should be something like that:
>>
>> if (env->ip & env->im)
>>          cpu_interrupt(env, CPU_INTERRUPT_HARD);
>> else
>> 	cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
>>
>> In cpu-exec.c you should do:
>>
>> if ((interrupt_request & CPU_INTERRUPT_HARD)) && (env->ie & IE_IE)) {
>>    [...]
>> }
>>
>> (Testing (env->ip & env->im) is not necessary because CPU_INTERRUPT_HARD
>> gives its state).
>>
>> You should also remove helper_update_interrupt().
> 
> The LM32 interrupt controller is integrated into the LM32 core. It is 
> controlled by that three registers (ie, im, ip) above. These registers are 
> set with a special opcode.
> 
> The main problem i had:
>   An interrupt is pending, but its masked. Then the program executes a write
>   to the interrupt mask register (remember its a special opcode), which
>   then should trigger an interrupt. (same with interrupt enable bit)
> 
> Thats the reason for that op helper above, which gets called after an update 
> to IE or IM.

In order to have a clearer view, you should consider the PIC as external 
  to the CPU and IM/IP/irq_state as a state of the PIC, not the CPU (you 
can implement CSR_IM and CSR_IP as callbacks to the PIC code).

The CPU only "sees" CPU_INTERRUPT_HARD = ((im & ip) != 0), which is set 
by the PIC as in your code. It also sees "IE".

In order to let IRQs be handled by the CPU, then you must terminate the 
translated block after instructions modifying IE/IP/IM (this is another 
problem in your code I forgot to spot).

Then helper_update_interrupt() can be removed.

[To be more precise, the QEMU CPU interrupt model assumes that there is 
only one hardware interrupt (CPU_INTERRUPT_HARD). This interrupt is only 
handled at the end of translated blocks. Translated blocks are 
dynamically chained, so it is *never* correct to set bits manually in 
"interrupt_request" because the translated block chaining must be 
removed so that control can be given back to the QEMU main loop to 
handle the interrupt requests. The consequence is that any instruction 
which potentially enables interrupts must terminates the translated 
block as soon as possible.]

> [...]

Regards,

Fabrice.




More information about the Devel mailing list