Successful Firmware Design Tips

May 16, 2016

So firmware can be a tricky jump for anyone with a background in the software domain, indeed many student's I've helped have struggled with the inherent parallel execution of firmware in comparison to the sequential programming of software and indeed the sequential manner in which we write firmware as text files. 


How to help get successful firmware designs? In my opinion along with understanding the theory digital systems, this is more about a rigorous methodology than hours and hours of design.


So top tips time...


  1. Draw up your specifications...

    1. Functionality

    2. Clocking

    3. Resets

    4. Interrupts

    5. Configuration

    6. Fabric Side Inputs/Outputs

    7. External Pin Inputs/Outputs

    8. Use of any existing protocols/standards (SPI, I2C, SerDes etc)

    9. Use of IPcores, either 3rd party or your own

    10. Define ALL states in state machines

    11. Define either pos-pos data clock transfer or pos-neg data clocking

    12. Utilise Design for Test (DFT) Methodology

    13. Utilise Design for Adaptability (DFAD) Methodologies

    14. Consider hiarchical and modular designs

    15. Consider your physical and timing constraints

    16. Consider all diferent clock domains and how to cross them

  2. If you can't draw it, then go back to your original specifications

    1. Draw a top level block diagram of the block

    2. Flesh out sub-blocks with logic diagrams

  3. Initial Design

    1. Simple functionality first, there is no need to jump right in with complex states or odd iteration modes of counters

    2. Force a good personal coding style

      1. Source header, revision history, to do list, simulation outcomes, synthesis outcomes, error/warning lists etc

      2. Add any source dependencies, list data sheets, user manuals, schematics

      3. Add any support or forum queries or external web links etc

    3. Ensure all registers have defined initial states, preferably all zeros

    4. Code all state machines to use Grey code or unary code for robustness

    5. Ensure all state machines are synchronous

  4. Functional Simulation

    1. Can all registers be reset?

    2. Can all registers be set?

    3. Is base functionality met?

    4. Correct data clock edges?

    5. Correct state evolution?

    6. What if block never gets an initial reset?

    7. What if block slips into an unused state code?

    8. What if an input is delayed by a random time period?

  5. Co-Simulation with either other blocks or models of connected blocks

    1. Check data transfer progression

    2. Use data valid flags to aid handshaking

    3. Use formal handshaking protocols if advantageous

    4. Use known patterns such as 0xFFFF, 0xFAFF or 0xABCD to indicate in the data stream when the block is in an erroneous state or a waiting state, 0x0000 can lead to debugging difficulties

    5. Try to use edge triggered events rather than level triggered

    6. Try to always be synchronous to your system clock, even if this required synchronously registering an asynchronous external signal.

  6. Design for code reuse and parameterise the code, for example make an SPI module N-bit rather than 16-bit

  7. Utilize the generate statement and compile time flags to aid in programability

  8. Check all declared wires/registers for connectivity

  9. Check all registers have inputs, outputs, clock, reset and hold conditions

    1. Remember the compiler will perform trimming if it thinks a register/wire is redundant

  10. Check Syntax

  11. Hunt out and remove any latches (unless explicitly coded)

  12. Perform an initial synthesis (only progress once clean)

    1. Remove all Errors, go back to initial design and functional simulation

    2. Remove simple warnings first as they often create ripple warnings

    3. Tackle compiler bit trimming as a priority

    4. Aim for a synthesis, pre-routed frequency 20% higher than your specification, so for 100MHz operation ensure your synthesis report says something like 120 to 130MHz etc. The routed design always is slower than this as the compiler adds in routing delays, which are not accounted for in a pre-routed timing report.

  13. Perform code to netlist translate

  14. Perform netlist to CLB mapping

    1. Remember that a CLB is formed by a LUT, multiplexer and flip flop and must have a clock and reset

  15. Perform design place and route

    1. Aid the clocking by using dedicated routing as far as possible

    2. Aid routing by forcing the block to be close to its critical FPGA pads (e.g. an SPI module should be close to its SCLK, SDI and SDO pins)

    3. Aid fast register-register clocking by forcing short routing delays, principally by using physical constraints

    4. Constrain the block to an area roughly 10% larger than its required resources

    5. Use timing constraints so the compiler knows system clock is fast and knows that a clock like an I2C clock is very slow.

    6. If a signal must traverse a large distance then consider a) clock buffering and b) adding data registers, latency in terms of clock cycles is preferable to lengthy RCL routing delays.

    7. Use FIFOs, Buffers, re-timing and handshaking to cross clock boundaries

  16. Use FPGA visualizers such as PlanAhead or FPGA Editor to check placement and clock/reset or data routing

  17. Where possible use the FPGAs internal PLLs, clock managers, clock dividers and dedicated clock routing to enable high speed clocking

  18. Do not use clock gating unless absolutely confident on glitch free operation and correct functionality

  19. Use state machines to force sequential operations

  20. Use locked, valid or ready flags to indicate when a sub-block is stable and use to control state machine iteration.

    1. If needed may need to slow the loop time of feedback loops and FSMs to ensure stability.



This is perhaps quite a brain dump of tips, but over time I will revisit this list and re-organise and formalise it as a teaching aid. Firmware can be very complex at times and particularly difficult to get your head round as a student.


Below is a rather out of date block diagram of the FLITES firmware system, the point being that personal organisation, sticking to a listing/checklist methodology and a modular design will help in the end and will produce good, reusable and configurable results. 



That's all for now.



Please reload

Firmware Design Engineer (Digital)

Leonardo MW Ltd.

Crewe Toll, Edinburgh, Scotland, UK

Dr Edward M.D. Fisher Ph.D MEng SMIEEE MIET

© 2020 by Edward Fisher. Proudly created with

  • Rg
  • orcidlogo_350x158
  • Twitter Social Icon
  • LinkedIn Social Icon