Embedded Systems
8-bit Microcontroller
16-bit Multiplication
Algorithm Optimization
MCU Performance

Faster 16bit multiplication algorithm for 8-bit MCU

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Multiplication in microcontroller units (MCUs) is a fundamental operation that underpins many computational tasks, but it can also be a performance bottleneck, especially in lower-end 8-bit MCUs lacking hardware multipliers. A typical challenge is multiplying 16-bit integers efficiently given the limited resources of these devices. In this article, we explore methods and an algorithm to speed up 16-bit multiplication on 8-bit MCUs using software-based techniques.

Basics of 16-bit Multiplication

On an 8-bit microcontroller, such as those from the AVR or PIC families, 16-bit multiplication must often be conducted in software. This typically involves combining four 8-bit multiplications to achieve a single 16-bit multiplication, due to the limited register width. A basic multiplication of two 16-bit numbers, A and B , could be represented as follows:

A=AH×256+ALA = A_{H} \times 256 + A_{L}B=BH×256+BLB = B_{H} \times 256 + B_{L}

Where AHA_H, ALA_L, BHB_H, and BLB_L are the high and low bytes of AA and BB, respectively. The resulting multiplication operation can be broken down into smaller segments:

Product=(A_H×256+A_L)×(B_H×256+B_L)Product = (A\_H \times 256 + A\_L) \times (B\_H \times 256 + B\_L)

Expanding this expression gives:

Product=A_H×B_H×65536+A_H×B_L×256+A_L×B_H×256+A_L×B_LProduct = A\_H \times B\_H \times 65536 + A\_H \times B\_L \times 256 + A\_L \times B\_H \times 256 + A\_L \times B\_L

Each of the terms can be calculated using an 8-bit multiplication.

Optimized Algorithm

To optimize the multiplication, a strategic approach can diminish the total number of operations by reusing partial results and minimizing additions. One such optimized method is the iterative shift-and-add processing which exploits the binary decomposition of the numbers.

Faster 16-bit Multiplication Algorithm

Here is a step-by-step explanation of an efficient method to multiply two 16-bit numbers:

  1. Initialize Registers: • Load the initial values of A and B into two pairs of 8-bit registers representing their high and low bytes.
  2. Compute Partial Products: • Compute AL×BLA_L \times B_L: This is the simplest multiplication as it directly contributes to the lower byte of the final product. • Compute AL×BHA_L \times B_H and AH×BLA_H \times B_L: These contribute mainly to the middle segment of the resulting word. Each multiplication here will need to be left-shifted by 8 bits (equivalent to multiplying by 256). • Compute AH×BHA_H \times B_H: This contributes to the higher byte and needs to be left-shifted by 16 bits in the final product assembly.
  3. Aggregate Partial Products with Shifting: • Add the results, as shown in the following combinatorial scheme, ensuring that carries from one byte are considered in the subsequent higher byte:

Low Byte: (A_L×B_L)Middle Byte: (A_L×B_H)+(A_H×B_L)+carry from low byteHigh Byte: (A_H×B_H)+carry from middle byte\begin{align*} &\text{Low Byte: } (A\_L \times B\_L) \\ &\text{Middle Byte: } (A\_L \times B\_H) + (A\_H \times B\_L) + \text{carry from low byte}\\ &\text{High Byte: } (A\_H \times B\_H) + \text{carry from middle byte} \end{align*}

  1. Optimize Carries Management: • Use assembly instructions wisely to manage carries that arise when adding 8-bit results. Adding with carry instructions (ADD /ADC in AVR assembly) efficiently manages the multi-byte aggregation.

Example Code

Below is an illustrative example in pseudocode that translates the above approach into steps suitable for a typical 8-bit AVR type MCU:

Instruction Cycle Count: Depending on the architecture, these operations (8-bit multiplication, additions, and carries) can be significantly faster when carefully sequenced compared to calling generic multiplication routines. • Memory Use and Efficiency: This implementation is efficient in terms of memory since it mainly uses registers. This is crucial for MCUs with limited RAM. • Scalability: This method scales well for slightly larger bit-widths with the same principle applied to segments of the binary representation.


Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.