A small correction to my own post:
On 12-01-16 01:11 , Niklas Holsti wrote:
> To test if interrupts can take effect after the instruction "bit set
> IMASK",
I meant to write, 'after the instruction AFTER the "bit set IMASK"', but
I omitted the second "after". Oops.
--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .
Reply by Niklas Holsti●January 15, 20122012-01-15
On 12-01-15 22:24 , alb wrote:
> On 1/15/2012 3:17 PM, Niklas Holsti wrote:
>> "Effect latency" means that the "bit set IMASK" does not take effect at
>> once, but only after a delay -- in this case, one cycle, which is
>> usually one instruction. See the table in the 21020 UM in section
>> 3.1.2.1. The UM also says in section E.2:
>>
>> "A write to any system register except USTAT1 or USTAT2 has one cycle of
>> latency before any changes are effective."
>>
>> This means that an interrupt may be handled after the "bit set IMASK"
>> instruction, and perhaps even after the next instruction -- this is not
>> entirely clear (to me) from the UM.
>>
...
>>
>> Suppose that foo() should increment a counter atomically. If the
>> assembly code is like this:
>>
>> bit set IMASK ... // mask interrupts
>> load counter into register
>> increment register
>> store register into counter
>> bit clear IMASK ... // unmask interrupts
>>
>> then the 1-cycle effect latency means that foo() may be interrupted
>> between the "bit set" and the "load counter", which is harmless because
>> the counter is not yet touched, but perhaps foo() can be interrupted
>> also after the "load counter", which would break the atomicity. Putting
>> at least one "nop" after "bit set" gives the new IMASK time to take
>> effect before the atomic region starts.
>>
>
> Hence the NOPs guarantee that if any interrupt is occurring it will
> interrupt a nop operation
I would say, it interrupts "at a nop"; it does not interrupt the nop itself.
> rather than my "uninterruptable" part of the
> code.
Exactly. The essential point is that the interrupt occurs before the
first instruction of the uninterruptible part.
> But if I then understood correctly the UM I should be only worried
> about the latency in system register write operation, no other latency
> is involved.
For interrupt masking, in order to create uninterruptible code regions,
I agree that the "effect latency" is the only important latency. But for
computing the interrupt response time, you must of course consider other
latencies, too.
> If this is the case one NOP will serve the purpose.
I think so, since the "effect latency" for IMASK is one cycle. But one
more NOP will not do much harm.
...
>> The same effect latency applies to unmasking, but it usually does no
>> harm, since it only delays the handling of any pending interrupt when it
>> is unmasked. In unusual cases, after unmasking an interrupt you may need
>> to be sure that any pending interrupt is actually handled, before the
>> code does something else, and then you have to take the effect latency
>> into account also for unmasking, and add a "nop" after the "bit clear
>> IMASK".
>
> Given the aforementioned latency, any part of code can be executed after
> the interrupt enabling and is guaranteed that pending interrupt will be
> served.
>
> n : bit clr IMASK
> n+1: bit set IMASK
> n+2: nop
>
> in this extreme case were interrupts are enabled and then disabled right
> after there's still one cycle (n+1) were pending interrupt are served,
> since IMASK will only be set in n+2.
That would be my guess, but I would not trust it for such an extreme
case, without testing.
>> Note that I haven't tested any of this, but my understanding of "effect
>> latency" seems to match that of Glen and Mac.
>>
>
> Now I'm curious, how would you test this if you were to write the code?
To test if interrupts can take effect after the instruction "bit set
IMASK", I would write an interrupt handler that sets a variable "flag"
to 1, and another function that is called repeatedly and has this form:
bit set IMASK ... // mask interrupt
store zero in flag
load flag
if flag is not zero
report that an interrupt can occur after "store zero in flag"
bit clear IMASK ... // unmask interrupt
I would let the code run for a while, while feeding a large number of
interrupts into it. I would expect some reports from the next-to-last
line, above, when an interrupt is handled between "store zero in flag"
and "if flag is not zero".
To test that the "nop" after "bit set IMASK" works, I would run the same
code, modified to have a nop between "bit set IMASK" and "store zero in
flag". This time, I would expect no reports from the next-to-last line.
I don't see any easy way to test if the code can be interrupted
immediately after "bit set IMASK" -- the tests that I can think of
cannot separate an interrupt immediately before this insruction, from
one immediately after.
--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .
Reply by alb●January 15, 20122012-01-15
On 1/15/2012 3:17 PM, Niklas Holsti wrote:
> "Effect latency" means that the "bit set IMASK" does not take effect at
> once, but only after a delay -- in this case, one cycle, which is
> usually one instruction. See the table in the 21020 UM in section
> 3.1.2.1. The UM also says in section E.2:
>
> "A write to any system register except USTAT1 or USTAT2 has one cycle of
> latency before any changes are effective."
>
> This means that an interrupt may be handled after the "bit set IMASK"
> instruction, and perhaps even after the next instruction -- this is not
> entirely clear (to me) from the UM.
>
Thanks for the explanation, it seems to me clearer now.
>> This is how I would have set a
>> function to be uninterruptable:
>>
>> foo() {
>> DISABLE_INTERRUPTS();
>> // do foo stuff here
>> ...
>> ENABLE_INTERRUPTS();
>> }
>
> Suppose that foo() should increment a counter atomically. If the
> assembly code is like this:
>
> bit set IMASK ... // mask interrupts
> load counter into register
> increment register
> store register into counter
> bit clear IMASK ... // unmask interrupts
>
> then the 1-cycle effect latency means that foo() may be interrupted
> between the "bit set" and the "load counter", which is harmless because
> the counter is not yet touched, but perhaps foo() can be interrupted
> also after the "load counter", which would break the atomicity. Putting
> at least one "nop" after "bit set" gives the new IMASK time to take
> effect before the atomic region starts.
>
Hence the NOPs guarantee that if any interrupt is occurring it will
interrupt a nop operation rather than my "uninterruptable" part of the
code. But if I then understood correctly the UM I should be only worried
about the latency in system register write operation, no other latency
is involved. If this is the case one NOP will serve the purpose.
>>
>> Interrupt latency is documented in the document as follows:
>>
>>> 3.6.1 Interrupt Latency
>>> The ADSP-21020 responds to interrupts in three stages: synchronization
>>> and latching (1 cycle), recognition (1 cycle), and branching to the
>>> interrupt
>>> vector (2 cycles). See Figure 3.10 on the next page. If an interrupt
>>> is forced
>>> in software by a write to a bit in IRPTL, it is recognized in the
>>> following
>>> cycle, and the two cycles of branching to the interrupt vector follow
>>> that.
>>
>> Therefore, when I DISABLE_INTERRUPTS I would *assume* that as soon as
>> IMASK is set in cycle n, in n+1 the hardware will still latch the
>> interrupt but not recognize and not branch to the interrupt vector.
>
> The effect latency on writing to IMASK means that this assumption is
> wrong, and the interrupt is not effectively masked until cycle n+2 or n+3.
>
>> On the contrary, when I ENABLE_INTERRUPT, I would *assume* that as soon
>> as IMASK is clear in cycle n, in n+1 the hardware will latch the
>> interrupt, n+2 will recognize and n+3 will branch to interrupt vector.
>
> The same effect latency applies to unmasking, but it usually does no
> harm, since it only delays the handling of any pending interrupt when it
> is unmasked. In unusual cases, after unmasking an interrupt you may need
> to be sure that any pending interrupt is actually handled, before the
> code does something else, and then you have to take the effect latency
> into account also for unmasking, and add a "nop" after the "bit clear
> IMASK".
Given the aforementioned latency, any part of code can be executed after
the interrupt enabling and is guaranteed that pending interrupt will be
served.
n : bit clr IMASK
n+1: bit set IMASK
n+2: nop
in this extreme case were interrupts are enabled and then disabled right
after there's still one cycle (n+1) were pending interrupt are served,
since IMASK will only be set in n+2.
>
> Note that I haven't tested any of this, but my understanding of "effect
> latency" seems to match that of Glen and Mac.
>
Now I'm curious, how would you test this if you were to write the code?
Reply by Niklas Holsti●January 15, 20122012-01-15
On 12-01-15 13:24 , alb wrote:
> On 1/13/2012 10:22 PM, glen herrmannsfeldt wrote:
>> In comp.dsp Mac Decman<dearman.mark@gmail.com> wrote:
>>
>>>> On 1/11/2012 11:45 PM, Mac Decman wrote:
>> [snip]
>>>>> #define ENABLE_INTERRUPTS() asm("bit set IMASK SOMEBITS; nop; nop;")
>>
>>>> Why the nops? I was just about doing something similar, but with no nops.
>>
>>> Not sure how many it takes on your processor. But I believe IMASK
>>> like MODE1 has an effect latancy of one or two.
>>
....
>
> Uhm, I guess I did not understood that.
"Effect latency" means that the "bit set IMASK" does not take effect at
once, but only after a delay -- in this case, one cycle, which is
usually one instruction. See the table in the 21020 UM in section
3.1.2.1. The UM also says in section E.2:
"A write to any system register except USTAT1 or USTAT2 has one cycle of
latency before any changes are effective."
This means that an interrupt may be handled after the "bit set IMASK"
instruction, and perhaps even after the next instruction -- this is not
entirely clear (to me) from the UM.
> This is how I would have set a
> function to be uninterruptable:
>
> foo() {
> DISABLE_INTERRUPTS();
> // do foo stuff here
> ...
> ENABLE_INTERRUPTS();
> }
Suppose that foo() should increment a counter atomically. If the
assembly code is like this:
bit set IMASK ... // mask interrupts
load counter into register
increment register
store register into counter
bit clear IMASK ... // unmask interrupts
then the 1-cycle effect latency means that foo() may be interrupted
between the "bit set" and the "load counter", which is harmless because
the counter is not yet touched, but perhaps foo() can be interrupted
also after the "load counter", which would break the atomicity. Putting
at least one "nop" after "bit set" gives the new IMASK time to take
effect before the atomic region starts.
>
> Interrupt latency is documented in the document as follows:
>
>> 3.6.1 Interrupt Latency
>> The ADSP-21020 responds to interrupts in three stages: synchronization
>> and latching (1 cycle), recognition (1 cycle), and branching to the interrupt
>> vector (2 cycles). See Figure 3.10 on the next page. If an interrupt is forced
>> in software by a write to a bit in IRPTL, it is recognized in the following
>> cycle, and the two cycles of branching to the interrupt vector follow that.
>
> Therefore, when I DISABLE_INTERRUPTS I would *assume* that as soon as
> IMASK is set in cycle n, in n+1 the hardware will still latch the
> interrupt but not recognize and not branch to the interrupt vector.
The effect latency on writing to IMASK means that this assumption is
wrong, and the interrupt is not effectively masked until cycle n+2 or n+3.
> On the contrary, when I ENABLE_INTERRUPT, I would *assume* that as soon
> as IMASK is clear in cycle n, in n+1 the hardware will latch the
> interrupt, n+2 will recognize and n+3 will branch to interrupt vector.
The same effect latency applies to unmasking, but it usually does no
harm, since it only delays the handling of any pending interrupt when it
is unmasked. In unusual cases, after unmasking an interrupt you may need
to be sure that any pending interrupt is actually handled, before the
code does something else, and then you have to take the effect latency
into account also for unmasking, and add a "nop" after the "bit clear
IMASK".
Note that I haven't tested any of this, but my understanding of "effect
latency" seems to match that of Glen and Mac.
--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .
Reply by alb●January 15, 20122012-01-15
On 1/13/2012 10:22 PM, glen herrmannsfeldt wrote:
> In comp.dsp Mac Decman <dearman.mark@gmail.com> wrote:
>
>>> On 1/11/2012 11:45 PM, Mac Decman wrote:
> [snip]
>>>> #define ENABLE_INTERRUPTS() asm("bit set IMASK SOMEBITS; nop; nop;")
>
>>> Why the nops? I was just about doing something similar, but with no nops.
>
>> Not sure how many it takes on your processor. But I believe IMASK
>> like MODE1 has an effect latancy of one or two.
>
> If I remember, for some processors that is intentional. You want to be
> able to enable interrupts before returning from the interrupt
> routine, but not until after the return. (I might be remembering the
> 8080.) If it comes too soon, you will overflow the stack!
Uhm, I guess I did not understood that. This is how I would have set a
function to be uninterruptable:
foo() {
DISABLE_INTERRUPTS();
// do foo stuff here
...
ENABLE_INTERRUPTS();
}
Interrupt latency is documented in the document as follows:
> 3.6.1 Interrupt Latency
> The ADSP-21020 responds to interrupts in three stages: synchronization
> and latching (1 cycle), recognition (1 cycle), and branching to the interrupt
> vector (2 cycles). See Figure 3.10 on the next page. If an interrupt is forced
> in software by a write to a bit in IRPTL, it is recognized in the following
> cycle, and the two cycles of branching to the interrupt vector follow that.
Therefore, when I DISABLE_INTERRUPTS I would *assume* that as soon as
IMASK is set in cycle n, in n+1 the hardware will still latch the
interrupt but not recognize and not branch to the interrupt vector.
On the contrary, when I ENABLE_INTERRUPT, I would *assume* that as soon
as IMASK is clear in cycle n, in n+1 the hardware will latch the
interrupt, n+2 will recognize and n+3 will branch to interrupt vector.
Again quoting the book:
> To process an interrupt, the program sequencer performs the following
> actions:
> 1. Outputs the appropriate interrupt vector on the program memory
> address.
> 2. Pushes the current PC value (return address) on the PC stack.
> 3. If the interrupt is either an external interrupt (IRQ3-0) or the internal
> timer interrupt, the program sequencer pushes the current ASTAT and
> MODE1 registers on the status stack.
> 4. Alters the interrupt mask pointer (IMASKP) to reflect the current
> interrupt nesting state. The nesting mode (NESTM) bit in the MODE1
> register determines whether all interrupts or only lower priority
> interrupts are masked during the service routine.
Given the fact that I'm dealing with IRQ3-0 only, why would I care about
the stack? I feel I'm missing something here.
>
> In the disable case, if you want to be sure, you would need the NOP.
>
> For the enable case, though, it would seem to me that it wouldn't
> cause much of a problem. Unless you specifically needed to be
> interrupted, a delay of a few insructions shouldn't be a problem.
>
Uhm, I think I have not understood you clearly. Are you talking about
enabling interrupts at the end of the interrupt service routine? In this
case the two nops will need to be executed before the RTI instruction,
hence no matter how many nops you put you may overflow the stack, since
another interrupt may be coming before you returned from the current
one. Am I totally off?
I need to say that my understanding is still very hazy, so it might be I
completely missed your point. I will definitely need to understand these
details better before implementing anything.
> -- glen
>
Reply by lang...@fonz.dk●January 13, 20122012-01-13
On 11 Jan., 23:45, Mac Decman <dearman.m...@gmail.com> wrote:
> On Wed, 11 Jan 2012 12:23:27 +0100, Alessandro Basili
>
>
>
> <alessandro.bas...@cern.ch> wrote:
> >On 1/11/2012 9:52 AM, Mac Decman wrote:
> >[...]
>
> [snip]
>
> >It's not clear yet to me whether the interrupt are latched (IRPTL
> >updated) if interrupts are disabled (IRPTEN=3D0). By the way, the target
> >is an ADSP21020.
> [snip]
>
> >> Mark DeArman
>
> For example
> #define ENABLE_INTERRUPTS() =A0 asm("bit set IMASK SOMEBITS; nop; nop;")
> #define DISABLE_INTERRUPTS() =A0asm("bit clr IMASK SOMEBITS; nop; nop;")
>
> Mark DeArman
that will eventually break, it assumes that imask is always the same
"somebits",
you need to set imask to what it was before you changed it, or you
might be
enabling/diabling interrupts that code elsewhere has disabled/enabled
I haven't used that dsp, but I'm quite sure that the irpten bit is the
right way
to do it, just remember not to enable interrupts unless they were
enabled when
you disabled them
-Lasse
Reply by glen herrmannsfeldt●January 13, 20122012-01-13
In comp.dsp Mac Decman <dearman.mark@gmail.com> wrote:
>>On 1/11/2012 11:45 PM, Mac Decman wrote:
[snip]
>>> #define ENABLE_INTERRUPTS() asm("bit set IMASK SOMEBITS; nop; nop;")
>>Why the nops? I was just about doing something similar, but with no nops.
> Not sure how many it takes on your processor. But I believe IMASK
> like MODE1 has an effect latancy of one or two.
If I remember, for some processors that is intentional. You want to be
able to enable interrupts before returning from the interrupt
routine, but not until after the return. (I might be remembering the
8080.) If it comes too soon, you will overflow the stack!
In the disable case, if you want to be sure, you would need the NOP.
For the enable case, though, it would seem to me that it wouldn't
cause much of a problem. Unless you specifically needed to be
interrupted, a delay of a few insructions shouldn't be a problem.
-- glen
Reply by Mac Decman●January 13, 20122012-01-13
On Fri, 13 Jan 2012 13:55:36 +0100, alb <alessandro.basili@cern.ch>
wrote:
>On 1/11/2012 11:45 PM, Mac Decman wrote:
>[snip]
>> For example
>> #define ENABLE_INTERRUPTS() asm("bit set IMASK SOMEBITS; nop; nop;")
>> #define DISABLE_INTERRUPTS() asm("bit clr IMASK SOMEBITS; nop; nop;")
>>
>
>Why the nops? I was just about doing something similar, but with no nops.
>
Not sure how many it takes on your processor. But I believe IMASK
like MODE1 has an effect latancy of one or two.
Mark DeArman
Reply by Mac Decman●January 13, 20122012-01-13
On Fri, 13 Jan 2012 12:41:08 +0100, alb <alessandro.basili@cern.ch>
wrote:
>I never asked "what is the pragma to
>disable interrupts yet continue to latch them".
Haha, Sorry I guess that is what I kept reading when I read your post.
>
>> The Analog Devices parts do not latch Interrupts when IRPTEN=0 or
>> atleast don't respond to them. That is on the same page of the
>> manual.
>>
Yes it was not on the same page. Infact, I'm not sure where it is.
But if memory serves when IRPTEN=0 the sequencer clears the latch
register on the next cycle.
Mark DeArman
Reply by alb●January 13, 20122012-01-13
On 1/11/2012 11:45 PM, Mac Decman wrote:
[snip]
> For example
> #define ENABLE_INTERRUPTS() asm("bit set IMASK SOMEBITS; nop; nop;")
> #define DISABLE_INTERRUPTS() asm("bit clr IMASK SOMEBITS; nop; nop;")
>
Why the nops? I was just about doing something similar, but with no nops.