Posts Tagged ‘interrupts’

On an ASIC, my ISR had to write a 1 in one place and a 0 in another place to acknowledge (ack) the interrupt. The hardware engineer I talked to tried to explain how one was an interrupt bit so that is why it needed a 1, but the other bit is a status bit it needed a 0 to clear the status. It was a little confusing; my ISR had to clear both bits before it could exit. In most ASICs I had dealt with, I wrote 1s to ack. In a few others, I wrote 0s. To come across one where I had to use both a 1 and a 0 was a new one.

Interrupts are a fundamental part of chips, but there is no standard way of implementing them. This leads to several problems:

A chip with blocks leveraged from several sources could have mixed interrupt methods.

Firmware drivers leveraged from one chip to another, or from one block to another, are prone to introducing defects.

Firmware engineers must first study the documentation to determine which method is being used.

Having firmware write a 1 to ack an interrupt is the best method to use. Most chips use it so it is more commonly known by firmware engineers. When the hardware issues an interrupt causing firmware to read the value in the interrupt register, there are 1s in the appropriate positions indicating which interrupt or interrupts occurred. So it is an easy step to use that value to ack the interrupt. Otherwise, firmware has to take a 1’s compliment of the value before writing it out. And firmware engineers have to remember to take that 1’s compliment everywhere the acking is done, whether acking with the value read from the interrupt register or using a constant (such as a #define) to specify which bit to use.

Best Practice: Design the interrupt module so that a 1 written to the interrupt register acks the interrupt.

Interrupt modules also have the ability to let firmware control whether or not a specific interrupt is allowed to propagate. I have seen this register called the “Enable” register for some chips and the “Mask” register for other chips. And I have also seen the “Mask” register in some chips use a 1 as a mask for allowing interrupts to propagate and other chips use a 0 to mask out the interrupt. Every time I come across an Interrupt “Mask” register, I have to first study the documentation to see if I should use a 0 or a 1.

The best term to use is “Enable” because it is clear in the reader’s mind that to “Enable” an interrupt, you write a 1.

Best Practice: Use “Enable” as the name of the register that controls which interrupts will propagate.

These are just a couple of aspects regarding interrupts that should be set as a standard. I will discuss more in future newsletters.

A common question engineers often wrestle with is how long hardware will take to do a requested task so firmware can take the next step. Engineers implement different designs (both in hardware and firmware) depending on the length of time, and these designs have varying impacts on hardware and firmware complexity and overall system performance. Understanding their ramifications during the design phase helps balance the load between hardware and firmware.

Based on the hardware and firmware implementation required, we can group these designs into three categories:

No Delay – Hardware completes the task almost immediately. Firmware can assume the task is immediately completed and can safely take the next step.

Short Delay – Hardware completes the task after a short delay. Firmware must wait momentarily for the task to complete before taking the next step.

Long Delay – Hardware completes the task after a long delay. The wait time is long enough that firmware should do other processing while waiting for the task to complete before it can take the next step.

Let’s take aborts in hardware as an example, since implementations exist in each of the three categories – no, short, and long delays. For some aborts there is no delay; it is a simple matter of returning back to the home or idle state, clearing counters and buffers, and completing other activities that can be done quickly. Such an operation is so quick that it is not necessary for hardware to add extra logic for a status or interrupt bit. In these cases, firmware can initiate the abort and simply move on to the next step, which may be to set up the hardware for the next job. The key is for hardware to complete the abort before firmware tries to access it again.

Best Practice: When the task in hardware is fast enough to complete before the next firmware access, hardware does not need to implement a status or interrupt bit for task completion.

Some abort implementations can take several clock cycles to complete, which means that firmware must wait for completion before accessing the block again. If it is a short delay, hardware should provide a status bit that firmware could poll, looping a few times until the task is done, then move on to the next step. If there is a long delay, then hardware should provide an interrupt bit that firmware will enable. Firmware will then do other processing while waiting for the interrupt to occur. Setting up, waiting and responding to an interrupt requires several CPU cycles with task swaps, context switches and semaphore handling. Thus, for firmware, polling a status bit is preferable to managing an interrupt if the task will be done after a short delay.

Where that line should be between short and long delays must be determined on a case-by-case basis and depends on the hardware platform, operating system and performance requirements. The dividing line could even move dynamically depending on the current operating conditions of the product. To give engineers the flexibility of moving that dividing line, the hardware for short and long delays should be the same, implemented with both a status bit and a maskable interrupt. This flexibility allows engineers to calculate or take measurements to count how many loops the polling is taking and determine if polling is acceptable or if interrupts are needed.

Best Practice: Implement both a status bit and a maskable interrupt bit to indicate completion of hardware tasks that take time to complete, whether a short or a long time.

For some blocks, the time the abort takes can vary from a short delay if the block is in an idle state to a long delay if the block is busy and needs to gracefully terminate. Since firmware cannot know the current state, it must always assume the worse case. If firmware wants to take advantage of the shorter aborts when they do occur, it could poll for several loops in case the task completes quickly. If not, then enable the interrupt and switch to another task.

To help engineers know how to implement the firmware, put in the block’s documentation the min and max abort times and the conditions in which they will occur. It could be something such as, “if the block is already idle, the abort will complete in 20ns, otherwise it will take 2-3us to complete.”

Best Practice: Document the min and max times that a hardware task will take, including the conditions and states that affect those times.

I used aborts for these examples, but the concepts apply for any firmware-initiated hardware task that could take time to complete. Implementing both status and interrupt bits for short- and long-delay hardware tasks allows firmware to balance the system load and performance by using polling loops or interrupts as appropriate.

Until the next interrupt (which will not occur for at least 1,000,000,000,000us)…