This paper discusses design practices and guidelines that will maximize the efficient utilization of registers and other storage elements in an embedded system IC. This can result in a shorter firmware development time, and less confusion on the part of firmware developers -- meaning fewer mistakes in the firmware code. The final effect of firmware-friendly register design is a cheaper development effort, and faster time to market for customers intending to use the IC in a product.
In any embedded system design, the most obvious method of communication between hardware and software is through the use of registers. Firmware can read registers to determine the state of the hardware and write registers to affect the operation and activity of the hardware.
A couple of decades ago this interface was pretty much taken for granted. The firmware engineer could memorize the register map in a few minutes and then learn the registers as he worked his way through the design. These days, when an embedded system may have over 1,000 registers, the logical, planned use of registers by hardware designers can cut months off the development cycle for the firmware engineers.
The hardware point of view
When a new hardware design is begun, one of the first items of engineering business is to do a top-down analysis of the proposed IC. The total IC design is broken down into smaller blocks by an IC architect. This person divides the circuit into blocks that can be handled by one or a few hardware designers. These small blocks may be further broken down as needed.
As a hardware designer works on his small portion of the overall IC, his concerns are as follows:
- What does this module do?
- How do I talk to other hardware modules (that is, how do the inputs and outputs work)?
- How can I make it work?
- How is this module controlled?
In this paper, I am concerned with the final bullet on the above list. The obvious answer to this bullet is "Use registers and interrupts". I have discussed interrupts in a previous EEdesign feature.
While some registers are obvious at the architecture level and are part of the original specification given to the hardware designer, some register bits are added as needed during the design effort. In other words, when the designer says to himself "I need a bit field to control that" or "I need a bit field to make that information available to the processor" he adds the required bit field to an existing or a new register. As he works through his design, eventually all needed bit fields have been defined and organized into registers.
This process works well to assure that the module does what is expected and can be controlled as desired. The small modules are then combined into bigger modules, and all registers are mapped into the memory space of the IC.
The firmware engineers are eventually presented with a massive specification, hundreds of pages in length, with hundreds of registers detailed in the document. In order to make the specification easier to use, the registers may be grouped according to the hardware module that contains them.
The firmware point of view
When a new firmware design is begun, the firmware engineers receive a massive specification (described above) and are told to write the code to make it work. The firmware designers then spend the next several months attempting to figure out how the part works. Frequent calls to the hardware designers are necessary, and sometimes sample code is requested for particularly obsure functionality that may not be clear in the specification.
The number of registers in the design prohibit any sane firmware engineer from attempting to memorize the register map. The address order, in the processor's memory space, of the hardware modules is memorized and the spec is referred to as needed to understand the individual registers and bit fields.
Because the various hardware blocks are designed by different engineers, the organization of the registers and bit fields within registers in one block may be very different from that in other blocks. All this means that, instead of concentrating on firmware design, the engineers writing the control code spend a large amount of time searching through the spec to find register and bit field references.
Eleven firmware friendly design ideas
Many of following suggestions for firmware friendly register design are aimed at decreasing the amount of time spent by firmware engineers in understanding the design. Some are aimed at improving development efficiency by improving the debug capabilities of the IC.
1 Any writeable register should allow the firmware to read back what was written.
The exception to this is W1C register bits used for interrupts. W1C bits should be used only for interrupts. See my EEdesign exclusive feature on interrupts.
2 All undefined or reserved bits should be read-only and should read back as zero.
This is simply less confusing to the firmware engineer who wants to ignore those bits. This will save the firmware engineer CPU clock cycles that would otherwise be spent to clear out unwanted bits.
3 Reading a register should not cause side effects.
These would include clearing, setting, or otherwise changing a register bit field. Other effects could be starting, restarting, or stopping an operation. Always provide control or "Go" bits for these purposes.
4 Large bit fields should be right justified to the boundary of the next-larger standard bit-field size.
Using odd or unusual bit field boundaries in the register definition makes for a hard to read register value when debugging is in progress. Any firmware engineer can read a hexidecimal value, deterimine the bit-field boundaries, and extract the value of a desired bit field, in his head, if the bit field is located at logical boundaries (See Figure 1.) If the bit fields are not on these logical boundaries the engineer will still read the hex value and extract the bit field values in his head, but he will be wrong a large percentage of the time.
5 Provide 8-bit and 16-bit access to all memory blocks.
This is especially critical for an embedded IC that may be targeted at many different kinds of processors. Whenever the processor is not specified you have to assume that someone is going to try to use your part with an 8-bit processor. If the embedded IC is an ASIC, designed for a single customer, and the processor is specified, then access capabilities need only be applied to the level required by the processor.
6 Pointer registers should always contain byte-specific addresses.
A "pointer register" is a register that contains an address. This may be the start address of a block of memory accessed by the hardware, a pointer to a selected memory location in a FIFO, etc. A pointer register should allow the firmware to access the indicated storage element on byte boundaries even if the storage element is 32-bit or 16-bit aligned.
If the hardware simply does not have the capability to provide this level of access, the lower bits should appear in the register but should be read-only and should read back the correct value (usually zero). It is also critically important for understanding the embedded logic that the address held by the pointer register need not be shifted to be used by the processor (see item 3, below).
7 Registers with similar bit field functions should be specified and designed in a consistent manner.
If, for example, several logic blocks have similar bit fields in their control or status registers, these should be located at exactly the same bit location in the corresponding registers. Figure 2 gives an example of two registers that contain some common bit fields and some that are different. The common bit fields are organized in each register such that the same bit position contains the same bit field in each register.
Note that even when the bit fields do not have the exact same name (such as bits 1-0 of the registers in the example) they are still placed in the same bit position if the essential function is the same. This increases the ease in which a customer engineer can understand each new hardware block. It shortens the learning curve and decreases time to market. This also improves the efficiency of debugging the design.
8 Hardware arbitration should be supplied for any storage elements that can be accessed by multiple hardware blocks.
Examples of this are data transfer buffers that can be written by the CPU and by data input channels. If the hardware does not handle the arbitration then the firmware must do so. This means extra code space is needed and the actual operation of the system is going to be slowed down.
The following are specific recommendations for common hardware access conflicts:
9 All hardware storage elements should be readable by firmware.
- 1) Provide double-buffering for any writeable element that may be used by the hardware asynchronous to the CPU access. When a new value is written by the processor, that value is held in the buffer until the current hardware operation, using the old value, completes. At this point the buffered value should be automatically stored to the functional register and become the current value.
- 2) Provide shadow-buffering for any readable element that may be changed by the hardware asynchronous to the CPU access. If a storage element can change while the processor is reading the location in memory the resulting race condition means that the firmware receives a bad value. A standard firmware technique for handling this is to read the unstable register several times and look for a consistent value across several reads. This is tedious for firmware developers, slows down the operation of the system, and really doesn't guarantee that the value read is good; it only guarantees that the value was the same at the times read.
- 3) Provide shadow-buffering for wide counters or state machines that may require multiple accesses for a full read from the target CPU. Note that if a 16-bit processor is accessing 17 or more bits then a multi-access read will be required. The same applies to any sized processor attempting to read a value larger than the processor's data bus width. The hardware must provide a buffering mechanism that stores the value in the remainder of the storage element when the CPU begins a multi-access read to view the contents of that storage element. If, for example, the 16-bit processor reads bits 15-0 of a 32-bit register, bits 31-16 of the register must be saved by the hardware in anticipation of a follow-up read to the upper 16 bits.
- 4) Provide wait state generation for the CPU or the data channel to any storage elements that can be accessed asynchronously by both. This can be done using a READY signal to the processor forcing the CPU to wait until the access by the competing channel is complete. Note that if a double-buffer or a shadow-buffer is provided, this should not preclude the capability to write directly to the active element, bypassing the buffer. It is usually dangerous and inadvisable to do this but the capability, if provided in a test/debug register capacity (see item 10), provides the firmware with additional hardware bug work-around capabilities.
Generally the status and control elements that are necessary for normal operation of the firmware are provided and easily accessed by the CPU. However, there are usually a huge number of storage elements that are not accessible to firmware at all. Storage elements include registers, counters, state machines, memory blocks, and anything else that can hold a state between clocks. Some flip-flops may be so fast that they are useless to firmware but it's easier for firmware to ignore a readable flop then to use a necessary but inaccessible flop.
Those memory elements which are not needed for normal operation should still be accessible for test and debug purposes. This greatly improves the firmware engineer's ability to debug a problem. This also means that, if calls to hardware support do become necessary, more complete data can be provided to support personnel. This also increases the chance that a firmware work-around to a hardware bug can be generated and used until a fixed version of the hardware becomes available. This is extremely important in today's world of million dollar masks and six month lead times.
Note that if all the storage elements were made visible to the processor in a flat memory map, the block of the memory map used by these storage elements may be too large to allow efficient normal operation of the IC. It can also be confusing to the firmware developer to see thousands of unneeded storage elements cluttering up the specification (which, as was already mentioned, is very big).
While all storage elements should be visible to the microprocessor, all those which are not needed for normal operation need not share a memory map with the normal registers. Provision should be provided for paged register maps to hold the extra storage elements that are provided only for debug and test capabilities. Documentation for these storage elements need not be in the standard specification and should be provided in a separate document supplied for debug purposes.
10 The firmware should be able to load or reset every counter and state machine in the hardware design.
It is fairly common at the present time for embedded systems to possess one or more reset registers that allow returning the state of any logic block to its Power-On Reset state. This minimal reset capability should be provided, but write capabilities are immensely more powerful. The reset capability should not necessarily be to a 'zero' state or to the Power-On Reset state but should be to a reasonable start-of-operation state.
The major resistance felt from hardware designers when confronted with this idea seems to be the gate count hit to the logic. Given the size of today's embedded ICs this hit is usually minor.
Another concern is the timing of massive address decode logic needed to provide access to the number of storage elements thus provided. This can be a serious problem, especially if access to a non-standard register requires paging to an appropriate debug register map first. This is a tough issue and may make the use of these registers on hardware bug work-arounds seem pointless. However, a slow work-around is better than a 3-6 month wait for new silicon.
The ability to perform powerful hardware error work-around functions in order to save on respins of the IC can often justify the cost of adding this capability to the design. If the volumes of the part justify a cost reduction, the debug and test logic can be designed to be removed for high volume production.
Intelligent storage element design can greatly improve firmware development cycles by providing easier to use products. This can result in faster times to market for those implementing an embedded system. One of the major benefits of following the storage element accessibility guidelines in this paper (items 9 and 10) is the ability to provide firmware workarounds to hardware errors in the embedded IC. This can save months of down time for the firmware design team who don't have to spend an extended amount of time waiting for a fix. This also saves a massive cost hit to the IC supplier who can wait until late in the development cycle to do a single respin to fix all the problems found in the IC.
David Fechser is a senior staff engineer working for the Systems Verification group of the Storage Products Division at LSI Logic Corp. David lives in Fort Collins, Colorado and can be contacted at 970-206-5678 (firstname.lastname@example.org).