-
-
Notifications
You must be signed in to change notification settings - Fork 794
Replace queue-based interrupts with NVIC regs #687
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
bradjc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And of course the issues with flash discussed on irc.
arch/cortex-m4/src/nvic.rs
Outdated
| @@ -0,0 +1,110 @@ | |||
| //! Cortex-M3 NVIC | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cortext-M4?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's just... like... your opinion man
|
Oh I also tested with the blink, hail, and rot13 apps all running concurrently and they seemed to work. |
| /* Set thread mode to privileged */ | ||
| mov r0, #0 | ||
| msr CONTROL, r0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
generic_isr is only called to service interrupts, correct? My reading of B1.3.1 of the ARM v7m ARM is that the processor should be in Handler mode, which is by definition already privileged. I don't think this is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is needed to make sure we're in privileged mode when we return the kernel, not for this handler's code.
arch/cortex-m4/src/lib.rs
Outdated
| ldr r1, =INTERRUPT_TABLE | ||
| ldr r0, [r1, r0] | ||
| /* r1 = NVIC.ICER[r0 / 32] */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From this comment, I expect one of the instructions below to be a memory read?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, it's taking an address: r1 = &NVIC.ICER[r0 / 32]
arch/cortex-m4/src/lib.rs
Outdated
| movt r1, #0xe000 | ||
| lsr r2, r0, #5 | ||
| mov r3, #4 | ||
| mul r2, r3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why load 4 into a register and multiply instead of just shifting again here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cause like... I don't know how to do that... would it just be lsr r2, r0, #7?
arch/cortex-m4/src/lib.rs
Outdated
| /* r2 = 1 << (r0 & 31) */ | ||
| mov r2, #1 | ||
| mov r3, #31 | ||
| and r3, r0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can consolidate these two instructions to just
and r3, r0, #31
arch/cortex-m4/src/nvic.rs
Outdated
| use kernel::common::volatile_cell::VolatileCell; | ||
|
|
||
| #[repr(C, packed)] | ||
| // Registers for the NVIC. Each |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each what? Don't leave me hanging! :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You get the answer when you buy the DLC
5ab0566 to
5482c8a
Compare
|
Rebased, fixedup, ported to NRF52, cortex-m0/nrf51, but need to test after the rebase and some cleanup. Last I tested thoroughly before the rebase, sam4l was working as was nrf52. More tomorrow |
4ecfbfc to
6d58a5f
Compare
|
Looks good, have you tested it on both nRF51-DK and nRF52-DK? |
|
@niklasad1 literally just tested right now, and after some fixes, it's all working. The one thing i noticed is that |
|
I think this is ready, maybe it could use some more assembly auditing from the venerable @ppannuto. I trust the assembly insofar as I've tested it, but @ppanuto's caught obvious things in the past that I've missed, and is also good at asking for the right documentation for assembly. |
bradjc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't look super thoroughly, just at the parts I've been looking at.
arch/cortex-m4/src/nvic.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
M0 now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gah! Too many files!!!
boards/hail/src/main.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't want this in Hail proper.
chips/sam4l/src/flashcalw.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, removed it and I trust you, but I needed it before your changes on master, so should test this just in case before merging (which I can do first thing tomorrow)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested. Works.
Instead of using a global queue to notify the event loop about pending interrups, this commit uses the built in NVIC pending bits themselves. This has a few benefits. First, it removes controller specific ISRs that do nothing but enqueue an interrupt event. Second, it makes this code generic for all Cortex-M4 chips (and should be ported to Cortex-M0 et al). As a result of both of these, it removes about 10kB of code on hail and imix. Third, it removes the need for controller drivers to handle enabling/disabling nvic lines themselves. Fourth, it's much faster since enqueing and dequeuing in the ring buffer is actually pretty expensive.
77ac17f to
b87b353
Compare
ppannuto
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just looked over the assembly
arch/cortex-m0/src/lib.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this comment still appropriate? (also weird spacing for this block?)
arch/cortex-m0/src/lib.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shift right 31? Is this supposed to be the r0 / 32 step? I'd expect that to be a shift right of 5 bits?
I think the readability here in general could be improve with some pedantry for commenting assembly, i.e.
asrs r3, r0, #5 /* r3 = r0 / 32 */
where every step lists its purpose. Assembly arithmetic is hard enough to justify this
arch/cortex-m4/src/lib.rs
Outdated
| /* NVIC.ICER[r0 / 32] = 1 << (r0 & 31) */ | ||
| movs r2, #1 | ||
| movs r3, #32 | ||
| sdiv r3, r0, r3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace these two with asr r3, r0, #5? Shorter and matches m0 implementation
arch/cortex-m0/src/lib.rs
Outdated
| /* NVIC.ICER[r0 / 32] = 1 << (r0 & 31) */ | ||
| movs r2, #31 | ||
| asrs r3, r0, #31 | ||
| ands r3, r2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I'm a bit more confused, as it looks like this is and'ing with the shifted r0? I think commenting each step will alleviate confusion here.
|
@ppannuto I cleaned up and commented the assembly for disabling nvics in the ISR. I think the problem was that I had compiled the assembly from C code that used signed (rather than unsigned) integers so GCC was be overly clever. I re-did it with unsigned ints and the result was good enough for me to understand and comment. |
e24c4c5 to
ce71eae
Compare
ppannuto
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me now. Only blocking thing I have left is the spelling of deferred :)
arch/cortex-m4/src/lib.rs
Outdated
| /* r0 = 1 << (r0 & 31) */ | ||
| movs r3, #1 /* r3 = 1 */ | ||
| and r0, r0, #31 /* r0 = r0 & r2 (31) */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: The assembly is right, the comment is wrong (r2 not involved here)
chips/nrf51/src/chip.rs
Outdated
| TIMER1 => nrf5x::timer::ALARM1.handle_interrupt(), | ||
| TIMER2 => nrf5x::timer::TIMER2.handle_interrupt(), | ||
| UART0 => uart::UART0.handle_interrupt(), | ||
| _ => debug!("NvicIdx not supported by Tock\r\n"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: don't need \r\n here, debug! adds the line endings for you
chips/sam4l/src/flashcalw.rs
Outdated
| GPFRLO, | ||
| } | ||
|
|
||
| static DEFERED_CALL: DeferedCall = unsafe { DeferedCall::new(Task::Flashcalw) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is pervasive -- and don't hate me -- s/defered/deferred
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ppannuto I couldn't hate you if I wanted to.
chips/sam4l/src/dma.rs
Outdated
|
|
||
| pub fn handle_interrupt(&mut self) { | ||
| let registers: &mut DMARegisters = unsafe { mem::transmute(self.registers) }; | ||
| registers.interrupt_disable.set(0xffffffff); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: you use !0 pretty much everywhere else
|
@alevy yeah, I have noticed that the But I haven't understood how to debug user-space applications so I have |
Pull Request Overview
Instead of using a global queue to notify the event loop about pending
interrups, this commit uses the built in NVIC pending bits themselves.
This has a few benefits:
al). As a result of both of these, it removes about 10kB of code on hail
and imix.
enabling/disabling nvic lines themselves.
Downsides?
Testing Strategy
In principle, this should be a pretty transparent change except some drivers relied on explicit nvic handling to disable interrupts. I believe I've fixed that in all cases, and have tested a number of the example apps on hail and imix. However, more comprehensive testing would be useful.Tested fairly extensively on Hail, NRF51-DK and NRF52-DK. On Hail, we've run a bunch of apps, including
tests/hail,rot13,test/nonvolatile_storage,blinkand on the NRFs we ranble_advertising,blink,tests/aes.TODO or Help Wanted
The flash driver has a particular place where it actually called the ISR explicitly from the code. That ISR no longer exists (and either way would be useless) and I don't understand what role exactly that was playing, or how to reproduce that functionality (perhaps by just callinghandle_interrupt, but why did the original code not just do that?).I left a TODO where that code used to be. Does anyone know how to trigger the issue that led to that hack?Documentation Updated
Kernel: The relevant files in/docshave been updated or no updates are required.Userland: The application README has been added, updated, or no updates are required.Formatting
make formatallhas been run.