I don't understand.
Each of those INTRO..INTPF instructions enables some type of interrupt. They are all INTON's of some sort. Only one INTOFF is needed to shut down whatever one's enabled.
Maybe I've got this too tangled up. How could it better represented in the instruction set?
Block/allow instructions would be more needed for data structures that you don't want the interrupt code to see in intermediate states.
I'm kind of leaning towards one instruction which toggles the interrupt blocking, but it's hard to think of a name for.
Other than data protection, I can see more general use for Enable/Disable INT.
A coarse disable would be possible via reloading the buried register with a very large value, but there is a just-need-a-litte-more-time use case, where main loop code could request to complete, before INT and provided that was inside 2 INT delays-INT action time, you would not lose INT cadence.
Obviously there is added jitter, but code like RTC would run with no lost ticks, up to just under 2 int delays.
Another disable INT use, would be to to allow swap-in of a different INT routine.
On each interrupt, a 'LINK $1F4,$1F5 WC,WZ' instruction is mux'd into the pipeline.
Here is how you could make a round-robin timed task switcher:
' Interrupt routine - $1F5 always points here' $1F1..$1F4 contain C/Z/PC's for different tasks.' Task is switched on each timer interrupt.
intcode mov temp,$1F4 mov $1F4,$1F3 mov $1F3,$1F2 mov $1F2,$1F1 mov $1F1,temp jmp $1F4 wc,wz
TIE would toggle the block/unblock, whereas INTOFF would shut down the interrupt source.
Then Block need to 'get into' the mnemonic.It is an INT opcode, so INTBT or INTBLKT makes it clear it is an interrupt behaviour modifier.or because it is also a Pause of Interrupt operation, INTPT for interrupt Pause Toggle ?
So they are either possible, or not. That's what TIE does. And we just make sure and only use the word enable here, so that it's clear.
The other cases are all about having an interrupt source or not.
INTX = source interrrupt from timer..
INTPX = source interrupt from any edge on pin...
INTOFF = turn interrupt source off.
Using "source" gets away from the overlapping terminology.
One can setup a source, but not have interrupts enabled kind of language would then make much better sense.
In a descriptive text, such as the round robin tasker:
On each interrupt, a 'LINK $1F4,$1F5 WC,WZ' instruction is mux'd into the pipeline.
Here is how you could make a round-robin timed task switcher sourced from the timer:
' Interrupt routine - $1F5 always points here' $1F1..$1F4 contain C/Z/PC's for different tasks.' Task is switched on each timer interrupt.
intcode mov temp,$1F4 mov $1F4,$1F3 mov $1F3,$1F2 mov $1F2,$1F1 mov $1F1,temp jmp $1F4 wc,wz
**should any task need exclusive access, interrupts could be disabled / enabled with the TIE instruction, which inhibits the active interrupt source when toggled on.
BTW: Re: All that pages and pages about interrupts.
Ugh. Where do I / we begin?
So don't. Chip is here now, and we don't have a tasker on this chip, and we have seen what good the tasker really did. If it's too hot, it's too hot. So long as this isn't too hot?
Game on.
Right.
Let's just pretty please make sure we get a chip this time. I can't take another "get good at it, wait, then nothing" cycle. Seriously.
Perhaps I missed something here, but if you have an instruction to enable an interrupt and one to disable an interrupt why would you want one to toggle it?
Is there a case where you would want to switch the state without knowing the current state?
There is the ability to interrupt or not. And yes, you may want to just turn them off for a bit without knowing all the interrupt state details. That's what TIE does.
Toggle Interrupt Enable.
There is the ability to source an interrupt from a pin edge, timer, etc... and that source can be turned off.
4 cases then:
1. TIE = 0 interrupts disabled, no interrupt sources INTOFF last excecuted. Nothing will happen.
2. TIE = 0 interrupts disabled, interrupt source specified, say the timer. Nothing will happen.
3. TIE = 1 interrupts disabled, no interrupt source. Nothing will happen.
4. TIE = 1 interrupts enabled, interrupt source specified, interrupt will happen.
A block of code that really doesn't want an interrupt may not know the source, so just running INTOFF sucks, because how does the source get turned on again?
So TIE exists to enable or disable interrupts, and the other instructions exist to specify a source, or no source.
Maybe this would be a clean interrupt implementation:
INTMOD D/# - sets interrupt mode. Value is 8 bits: mmpppppp mm: 00 - timer 01 - falling edge of pin 10 - rising edge of pin 11 - either edge of pin pppppp: pin index (0-63), ignored when mm = 00
INTPER D/# - set the interrupt period (0 disables interrupts)When in timer mode, this is how long to delay between insertion of LINK instructions. When in pin mode, this is how long of a delay after a LINK instruction is inserted before the interrupt is active again.
INTHLD - hold interrupt (used with INTREL)This prevents the LINK from being inserted, but it does not stop the interrupt from occurring. This allows for atomic operations.
INTREL - release interrupt (used with INTHLD)Allows LINK instruction to be inserted when an interrupt occurs. If an interrupt occurred while INTHLD was active, INTREL will cause a LINK instruction to be immediately inserted.
There is the ability to interrupt or not. And yes, you may want to just turn them off for a bit without knowing all the interrupt state details. That's what TIE does.
A risk with a simple toggle, is if the INT is disabled, and the code thinks it is enabled, TIE does the opposite of what the user expected.A Pause and UnPause would be always safe, applying that to a INT not yet enabled, would no nothing.
INTHLD (or INTHOLD) and INTREL make sense rather than TIE. Toggles are not my favourite way of doing things.
Is it possible to have more than one interrupt source enabled at a time?
If so, What if you just want to turn one interrupt source off?
It would be advantageous to have a timer interrupt plus another interrupt source. This could work like WAITPxx xxxx WC.
In fact, by utilising
INTPX/INTPR/INTPF and also INTPE/INTPNE we could dispense with WAITPxE/WAITPxN altogether and just use the interrupt mechanism. Then to reduce power, a WAITINT would just wait for an interrupt.
Perhaps the other waits (WAITVID) could work this way too?
Cluso99 said:
In fact, by utilising
INTPX/INTPR/INTPF and also INTPE/INTPNE we could dispense with WAITPxE/WAITPxN altogether and just use the interrupt mechanism. Then to reduce power, a WAITINT would just wait for an interrupt.
Perhaps the other waits (WAITVID) could work this way too?
WAITVID is gone already. Video/DACs are DMA'd now.
The other waits are still important though. There is nothing else that is so precise and responsive. Eg: Interrupts are going to be several clocks of lag before the jump even occurs. And on top of that there is context saving to handle, which most definitely is not the case when using WAITs. And, of course, context restore, atomic management and other resource sharing issues can be stacked on top of that in terms of jitter and overall loop time.
In terms of setup of IRQ source, I'd guess there is going to be config registers in the Smartpins that will set things like source, edge/level detection and polarity. The smart modes already going into the pin/counter handling will do much of the work me thinks. No need to add more instructions there.
All that said, the idea of combining WAITs with IRQ might be possible. In theory any of the existing pin wait combinations could be a singular IRQ or just used for the wait instructions when interrupts not enabled. It would presumably be a bit of re-engineering to keep most of the interrupt source logic in the Cog. I'm not sure how the Smartpins counters could be married into that though.
Maybe this would be a clean interrupt implementation:
INTMOD D/# - sets interrupt mode. Value is 8 bits: mmpppppp mm: 00 - timer 01 - falling edge of pin 10 - rising edge of pin 11 - either edge of pin pppppp: pin index (0-63), ignored when mm = 00
INTPER D/# - set the interrupt period (0 disables interrupts)When in timer mode, this is how long to delay between insertion of LINK instructions. When in pin mode, this is how long of a delay after a LINK instruction is inserted before the interrupt is active again.
INTHLD - hold interrupt (used with INTREL)This prevents the LINK from being inserted, but it does not stop the interrupt from occurring. This allows for atomic operations.
INTREL - release interrupt (used with INTHLD)Allows LINK instruction to be inserted when an interrupt occurs. If an interrupt occurred while INTHLD was active, INTREL will cause a LINK instruction to be immediately inserted.
I really like the most this scheme, but I'll extend the INTMOD to 9 bits:The MSB can become the set/query qualifier:
- If the 9th bit is 1 the other 8 bits sets the interrupt sources- If the 9th bit is 0 the other 8 bits represent the mask upon which the enabled/disabled sources are verified. And an AND between the mask and the current enabled source state can set the Z flag
And I'll love also the WAITINT and agree that the present other WAITs should remain.
I just finished the whole implementation and tested it. It seems to work fine.
The LE count of the cog increased by 2.7%.
I need to clean it all up and make sure it's as efficient as can be and its timing paths don't stick out.
After that, I'll resume the general clean-up effort on the whole Verilog design that was underway before this interrupt occurred.
Now, I know this interrupt thing is kind of different, and goes against established orthodoxy, especially my own. We probably shouldn't speak about any of this above a whisper, even in our own minds, for a while. We don't need any crises of conscience at this stage of the game.
Here is an example of the timer interrupt. The code below runs and the action is captured on the scope. D1 and D0 on the scope are P1 and P0 on the Prop2:
dat org
mov dira,#%11 'make pins 1..0 outputs
mov $1F5*4,#intcode 'set interrupt vector
intx #100 'interrupt every 100 clocks
loop xor outa,#%01 'main loop, toggle pin 0 jmp @loop
intcode xor outa,#%10 'interrupt, toggle pin 1 jmp $1F4*4 'return to main loop
Comments
I don't understand.
Each of those INTRO..INTPF instructions enables some type of interrupt. They are all INTON's of some sort. Only one INTOFF is needed to shut down whatever one's enabled.
Maybe I've got this too tangled up. How could it better represented in the instruction set?
Block/allow instructions would be more needed for data structures that you don't want the interrupt code to see in intermediate states.
I'm kind of leaning towards one instruction which toggles the interrupt blocking, but it's hard to think of a name for.
Other than data protection, I can see more general use for Enable/Disable INT.
A coarse disable would be possible via reloading the buried register with a very large value, but there is a just-need-a-litte-more-time use case, where main loop code could request to complete, before INT and provided that was inside 2 INT delays-INT action time, you would not lose INT cadence.
Obviously there is added jitter, but code like RTC would run with no lost ticks, up to just under 2 int delays.
Another disable INT use, would be to to allow swap-in of a different INT routine.
Good points.
Here is how you could make a round-robin timed task switcher:
' Interrupt routine - $1F5 always points here' $1F1..$1F4 contain C/Z/PC's for different tasks.' Task is switched on each timer interrupt.
intcode mov temp,$1F4 mov $1F4,$1F3 mov $1F3,$1F2 mov $1F2,$1F1 mov $1F1,temp jmp $1F4 wc,wz
There is some ambiguity about interrupts being enabled/disabled and blocked/allowed. We need to find some mnemonics that help reduce the blur.
CZL- 1101011 000 CCCC 000000000 000110000 TIE (toggle interrupt enable, enable initially set by INTRO..INTPFCZL- 1101011 000 CCCC 000000000 000110001 INTOFF (disable interrupt)CZL- 1101011 000 CCCC 000000000 000110010 INTRO (enable interrupt on transfer rollover, allows background Goertzel)CZL- 1101011 000 CCCC 000000000 000110011 INTBW (enable interrupt on block wrap, allows background FBLOCK adjustments)CZL- 1101011 00L CCCC 000000000 000110100 INTX D/# (enable interrupt on every D/# clocks)CZL- 1101011 00L CCCC 000000000 000110101 INTPX D/# (enable any-edge interrupt on pin D/#, Q captured for hold-off count)CZL- 1101011 00L CCCC 000000000 000110110 INTPR D/# (enable pos-edge interrupt on pin D/#, Q captured for hold-off count)CZL- 1101011 00L CCCC 000000000 000110111 INTPF D/# (enable neg-edge interrupt on pin D/#, Q captured for hold-off count)
Looks fine - how does TIE differ from INTOFF ?
CZL- 1101011 000 CCCC 000000000 000110000 TIE (toggle interrupt enable, enable initially set by INTRO..INTPFCZL- 1101011 000 CCCC 000000000 000110001 INTOFF (disable interrupt)CZL- 1101011 000 CCCC 000000000 000110010 INTRO (enable interrupt on transfer rollover, allows background Goertzel)CZL- 1101011 000 CCCC 000000000 000110011 INTBW (enable interrupt on block wrap, allows background FBLOCK adjustments)CZL- 1101011 00L CCCC 000000000 000110100 INTX D/# (enable interrupt on every D/# clocks)CZL- 1101011 00L CCCC 000000000 000110101 INTPX D/# (enable any-edge interrupt on pin D/#, Q captured for hold-off count)CZL- 1101011 00L CCCC 000000000 000110110 INTPR D/# (enable pos-edge interrupt on pin D/#, Q captured for hold-off count)CZL- 1101011 00L CCCC 000000000 000110111 INTPF D/# (enable neg-edge interrupt on pin D/#, Q captured for hold-off count)
Looks fine - how does TIE differ from INTOFF ?
TIE would toggle the block/unblock, whereas INTOFF would shut down the interrupt source.
It's a pity we can use hieroglyphics... 1)man scratching head ... 2)old woman pulling at child between two adults...
An arrow into a crow flying above a mouse eating grain.
Reserve enable disable doe the tie instruction.
Leave intoff the same, and phrase the others as something like "source interrupt from pin, timer, whatever"
People see a source or its all turned off. Then they see global enable disable.
TIE would toggle the block/unblock, whereas INTOFF would shut down the interrupt source.
Then Block need to 'get into' the mnemonic.It is an INT opcode, so INTBT or INTBLKT makes it clear it is an interrupt behaviour modifier.or because it is also a Pause of Interrupt operation, INTPT for interrupt Pause Toggle ?
TIE = toggle interrupt enable
So they are either possible, or not. That's what TIE does. And we just make sure and only use the word enable here, so that it's clear.
The other cases are all about having an interrupt source or not.
INTX = source interrrupt from timer..
INTPX = source interrupt from any edge on pin...
INTOFF = turn interrupt source off.
Using "source" gets away from the overlapping terminology.
One can setup a source, but not have interrupts enabled kind of language would then make much better sense.
In a descriptive text, such as the round robin tasker:
On each interrupt, a 'LINK $1F4,$1F5 WC,WZ' instruction is mux'd into the pipeline.
Here is how you could make a round-robin timed task switcher sourced from the timer:
' Interrupt routine - $1F5 always points here' $1F1..$1F4 contain C/Z/PC's for different tasks.' Task is switched on each timer interrupt.
intcode mov temp,$1F4 mov $1F4,$1F3 mov $1F3,$1F2 mov $1F2,$1F1 mov $1F1,temp jmp $1F4 wc,wz
**should any task need exclusive access, interrupts could be disabled / enabled with the TIE instruction, which inhibits the active interrupt source when toggled on.
Ugh. Where do I / we begin?
So don't. Chip is here now, and we don't have a tasker on this chip, and we have seen what good the tasker really did. If it's too hot, it's too hot. So long as this isn't too hot?
Game on.
Right.
Let's just pretty please make sure we get a chip this time. I can't take another "get good at it, wait, then nothing" cycle. Seriously.
Is there a case where you would want to switch the state without knowing the current state?
Toggle Interrupt Enable.
There is the ability to source an interrupt from a pin edge, timer, etc... and that source can be turned off.
4 cases then:
1. TIE = 0 interrupts disabled, no interrupt sources INTOFF last excecuted. Nothing will happen.
2. TIE = 0 interrupts disabled, interrupt source specified, say the timer. Nothing will happen.
3. TIE = 1 interrupts disabled, no interrupt source. Nothing will happen.
4. TIE = 1 interrupts enabled, interrupt source specified, interrupt will happen.
A block of code that really doesn't want an interrupt may not know the source, so just running INTOFF sucks, because how does the source get turned on again?
So TIE exists to enable or disable interrupts, and the other instructions exist to specify a source, or no source.
INTMOD D/# - sets interrupt mode. Value is 8 bits: mmpppppp mm: 00 - timer 01 - falling edge of pin 10 - rising edge of pin 11 - either edge of pin pppppp: pin index (0-63), ignored when mm = 00
INTPER D/# - set the interrupt period (0 disables interrupts)When in timer mode, this is how long to delay between insertion of LINK instructions. When in pin mode, this is how long of a delay after a LINK instruction is inserted before the interrupt is active again.
INTHLD - hold interrupt (used with INTREL)This prevents the LINK from being inserted, but it does not stop the interrupt from occurring. This allows for atomic operations.
INTREL - release interrupt (used with INTHLD)Allows LINK instruction to be inserted when an interrupt occurs. If an interrupt occurred while INTHLD was active, INTREL will cause a LINK instruction to be immediately inserted.
A risk with a simple toggle, is if the INT is disabled, and the code thinks it is enabled, TIE does the opposite of what the user expected.A Pause and UnPause would be always safe, applying that to a INT not yet enabled, would no nothing.
Is it possible to have more than one interrupt source enabled at a time?
If so, What if you just want to turn one interrupt source off?
It would be advantageous to have a timer interrupt plus another interrupt source. This could work like WAITPxx xxxx WC.
In fact, by utilising
INTPX/INTPR/INTPF and also INTPE/INTPNE we could dispense with WAITPxE/WAITPxN altogether and just use the interrupt mechanism. Then to reduce power, a WAITINT would just wait for an interrupt.
Perhaps the other waits (WAITVID) could work this way too?
INTPX/INTPR/INTPF and also INTPE/INTPNE we could dispense with WAITPxE/WAITPxN altogether and just use the interrupt mechanism.
I don't think WAITPxx can be removed as there is only one INT counter, and many possible places to use WAITPxx.
Then to reduce power, a WAITINT would just wait for an interrupt.
However, I like the idea of WAITINT for power saving yields.
Sorry guys couldn't resist!
Cluso99 said:
In fact, by utilising
INTPX/INTPR/INTPF and also INTPE/INTPNE we could dispense with WAITPxE/WAITPxN altogether and just use the interrupt mechanism. Then to reduce power, a WAITINT would just wait for an interrupt.
Perhaps the other waits (WAITVID) could work this way too?
WAITVID is gone already. Video/DACs are DMA'd now.
The other waits are still important though. There is nothing else that is so precise and responsive. Eg: Interrupts are going to be several clocks of lag before the jump even occurs. And on top of that there is context saving to handle, which most definitely is not the case when using WAITs. And, of course, context restore, atomic management and other resource sharing issues can be stacked on top of that in terms of jitter and overall loop time.
INTMOD D/# - sets interrupt mode. Value is 8 bits: mmpppppp mm: 00 - timer 01 - falling edge of pin 10 - rising edge of pin 11 - either edge of pin pppppp: pin index (0-63), ignored when mm = 00
INTPER D/# - set the interrupt period (0 disables interrupts)When in timer mode, this is how long to delay between insertion of LINK instructions. When in pin mode, this is how long of a delay after a LINK instruction is inserted before the interrupt is active again.
INTHLD - hold interrupt (used with INTREL)This prevents the LINK from being inserted, but it does not stop the interrupt from occurring. This allows for atomic operations.
INTREL - release interrupt (used with INTHLD)Allows LINK instruction to be inserted when an interrupt occurs. If an interrupt occurred while INTHLD was active, INTREL will cause a LINK instruction to be immediately inserted.
I really like the most this scheme, but I'll extend the INTMOD to 9 bits:The MSB can become the set/query qualifier:
- If the 9th bit is 1 the other 8 bits sets the interrupt sources- If the 9th bit is 0 the other 8 bits represent the mask upon which the enabled/disabled sources are verified. And an AND between the mask and the current enabled source state can set the Z flag
And I'll love also the WAITINT and agree that the present other WAITs should remain.
The LE count of the cog increased by 2.7%.
I need to clean it all up and make sure it's as efficient as can be and its timing paths don't stick out.
After that, I'll resume the general clean-up effort on the whole Verilog design that was underway before this interrupt occurred.
Now, I know this interrupt thing is kind of different, and goes against established orthodoxy, especially my own. We probably shouldn't speak about any of this above a whisper, even in our own minds, for a while. We don't need any crises of conscience at this stage of the game.
dat org
mov dira,#%11 'make pins 1..0 outputs
mov $1F5*4,#intcode 'set interrupt vector
intx #100 'interrupt every 100 clocks
loop xor outa,#%01 'main loop, toggle pin 0 jmp @loop
intcode xor outa,#%10 'interrupt, toggle pin 1 jmp $1F4*4 'return to main loop