UPGRADE YOUR BROWSER
We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!
This latest instalment of Adam Taylor's blog covers fixed-point math for implementation in the ARM-based Zynq SoC's programmable logic to improve performance.
In the last instalment of this blog—which has now been going weekly for six months now—we implemented a transfer function within the Zynq SoC’s Processor System (PS) side and crudely measured its calculation time. In this blog we start looking at what we need to understand and what we need to do to add VHDL code (or Verilog if you so desire) to the peripheral we created previously to implement and accelerate the same transfer function. We will be using a fixed-point number system to do this. Therefore, this blog looks at how fixed-point math works and how we can implement it correctly within the programmable logic (PL) side of the Zynq SoC.
There are two methods of representing numbers within a design: fixed point or floating point. Fixed-point representation maintains the decimal point at a fixed position, which greatly simplifies arithmetic operations. A fixed-point number consists of two parts called the integer and fractional parts as shown in this figure:
The integer part of the number is to the left of the implied decimal point and the fractional part is on the right. The above fixed-point number is capable of representing an unsigned number of between 0.0 and 255.9906375 or a signed number of between –128.9906375 and 127.9906375 using twos-complement representation.
Floating point numbers are divided into two parts the exponent and the mantissa. Floating-point representation allows the decimal point to float within the number depending upon the value’s magnitude.
The major drawback of fixed-point representation is that to represent larger numbers or to achieve a more accurate result with fractional numbers, you need more bits. Although FPGA’s can support both fixed and floating point numbers, most applications employ fixed-point number systems because they are simpler to implement than floating-point ones.
Within a design we can choose to use either unsigned or signed numbers. Typically, the choice is constrained by the algorithm being implemented. Unsigned numbers can represent a range of 0 to 2n – 1, and always represent positive numbers. Signed numbers use the twos-complement number system to represent both positive and negative numbers. The twos complement number system allows subtraction of one number from another simply by adding the two numbers. The range a twos-complement number can represent is:
- (2n-1) to + (2n-1 – 1)
The normal way of representing the split between integer and fractional bits within a fixed-point number is x,y where x represents the number of integer bits and y the number of fractional bits. For example 8,8 represents 8 integer bits and 8 fractional bits while 16,0 represents 16 integer and 0 fractional.
In many cases, the number of integer and fractional bits will be made at design time, normally following conversion of an algorithm from floating point. Thanks to the flexibility of FPGA’s, we can represent a fixed-point number of any bit length; we’re not limited to 32-, 64- or even 128-bit registers. FPGAs are equally happy with 15-, 37-, or 1024-bit registers. We can scale the hardware to fit the problem exactly.
The number of required integer bits depends upon the maximum integer value the number is required to store. The number of fractional bits depends upon the desired accuracy of the final result.
To determine the number of integer bits required, we can use the following equation:
For example the number of integer bits required to represent a value between 0.0 and 423.0 is:
We need 9 integer bits, allowing a range of 0 to 511 to be represented.
The decimal points of both fixed-point operands must be aligned to add, subtract, or divide the two numbers. That is, an x,8 number can only added to, subtracted from, or divided by a number that’s also in an x,8 representation. To perform arithmetic operations on numbers of different x,y formats, we must first align the decimal points. Note it is not strictly necessary to align the decimal points for division. However, implementing fixed-point division requires careful consideration to ensure that the result is scaled correctly in this case and not negative.
Similarly, the decimal points do not need to be aligned when multiplying two fixed-point numbers together. Multiplication provides a result that is X1 + X2, Y1 + Y2 wide. To clarify, multiplying two fixed-point numbers formatted as 14,2 and 10,6 produces a 24,8 result (formatted as 24 integer bits and 8 fractional bits).
For division by fixed constants, we can of course simplify the design by calculating the reciprocal of the constant and then using that constant result as a multiplier. Often, this technique results in a more efficient design implementation.
With this explanation of fixed-point math as a preface, we can progress to looking at implementing a function within the FPGA using fixed-point number systems in the next instalment of this blog series.
Incidentally I am speaking at EElive! this week in San Jose, California. If you are attending the event and see me, please stop and say “hello.” I’d love to meet you. Here’s my schedule.
Please see the previous entries in this MicroZed series by Adam Taylor:
The Zynq PS/PL, Part Five: Adam Taylor’s MicroZed Chronicles Part 25
The Zynq PS/PL, Part Four: Adam Taylor’s MicroZed Chronicles Part 24
The Zynq PS/PL, Part Three: Adam Taylor’s MicroZed Chronicles Part 23
The Zynq PS/PL, Part Two: Adam Taylor’s MicroZed Chronicles Part 22
The Zynq PS/PL, Part One: Adam Taylor’s MicroZed Chronicles Part 21
Introduction to the Zynq Triple Timer Counter Part Four: Adam Taylor’s MicroZed Chronicles Part 20
Introduction to the Zynq Triple Timer Counter Part Three: Adam Taylor’s MicroZed Chronicles Part 19
Introduction to the Zynq Triple Timer Counter Part Two: Adam Taylor’s MicroZed Chronicles Part 18
Introduction to the Zynq Triple Timer Counter Part One: Adam Taylor’s MicroZed Chronicles Part 17
The Zynq SoC’s Private Watchdog: Adam Taylor’s MicroZed Chronicles Part 16
Implementing the Zynq SoC’s Private Timer: Adam Taylor’s MicroZed Chronicles Part 15
MicroZed Timers, Clocks and Watchdogs: Adam Taylor’s MicroZed Chronicles Part 14
More About MicroZed Interrupts: Adam Taylor’s MicroZed Chronicles Part 13
MicroZed Interrupts: Adam Taylor’s MicroZed Chronicles Part 12
Using the MicroZed Button for Input: Adam Taylor’s MicroZed Chronicles Part 11
Driving the Zynq SoC's GPIO: Adam Taylor’s MicroZed Chronicles Part 10
Meet the Zynq MIO: Adam Taylor’s MicroZed Chronicles Part 9
MicroZed XADC Software: Adam Taylor’s MicroZed Chronicles Part 8
Getting the XADC Running on the MicroZed: Adam Taylor’s MicroZed Chronicles Part 7
A Boot Loader for MicroZed. Adam Taylor’s MicroZed Chronicles, Part 6
Figuring out the MicroZed Boot Loader – Adam Taylor’s MicroZed Chronicles, Part 5
Running your programs on the MicroZed – Adam Taylor’s MicroZed Chronicles, Part 4
Zynq and MicroZed say “Hello World”-- Adam Taylor’s MicroZed Chronicles, Part 3
Adam Taylor’s MicroZed Chronicles: Setting the SW Scene
Bringing up the Avnet MicroZed with Vivado