Successful Firmware Design Tips

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...

  2. Functionality

  3. Clocking

  4. Resets

  5. Interrupts

  6. Configuration

  7. Fabric Side Inputs/Outputs

  8. External Pin Inputs/Outputs

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

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

  11. Define ALL states in state machines

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

  13. Utilise Design for Test (DFT) Methodology

  14. Utilise Design for Adaptability (DFAD) Methodologies

  15. Consider hiarchical and modular designs

  16. Consider your physical and timing constraints

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

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

  19. Draw a top level block diagram of the block

  20. Flesh out sub-blocks with logic diagrams

  21. Initial Design

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

  23. Force a good personal coding style

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

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

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

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

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

  29. Ensure all state machines are synchronous

  30. Functional Simulation

  31. Can all registers be reset?

  32. Can all registers be set?

  33. Is base functionality met?

  34. Correct data clock edges?

  35. Correct state evolution?

  36. What if block never gets an initial reset?

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

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

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

  40. Check data transfer progression

  41. Use data valid flags to aid handshaking

  42. Use formal handshaking protocols if advantageous

  43. 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

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

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

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

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

  48. Check all declared wires/registers for connectivity

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

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

  51. Check Syntax

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

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

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

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

  56. Tackle compiler bit trimming as a priority

  57. 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.

  58. Perform code to netlist translate

  59. Perform netlist to CLB mapping

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

  61. Perform design place and route

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

  63. 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)

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

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

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

  67. 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.

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

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

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

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

  72. Use state machines to force sequential operations

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

  74. 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.


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