Skip to content

Commit dda161c

Browse files
committed
Add multiply & divide implementations for 128-bit unsigned integers.
1 parent 74c3b73 commit dda161c

3 files changed

Lines changed: 121 additions & 0 deletions

File tree

firmware/common/u128.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2026 Great Scott Gadgets <info@greatscottgadgets.com>
3+
*
4+
* This file is part of HackRF.
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2, or (at your option)
9+
* any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; see the file COPYING. If not, write to
18+
* the Free Software Foundation, Inc., 51 Franklin Street,
19+
* Boston, MA 02110-1301, USA.
20+
*/
21+
22+
#include "u128.h"
23+
24+
/* From https://stackoverflow.com/a/58381061 */
25+
26+
u128 u128_multiply(uint64_t lhs, uint64_t rhs)
27+
{
28+
uint64_t lo_lo = (lhs & 0xFFFFFFFF) * (rhs & 0xFFFFFFFF);
29+
uint64_t hi_lo = (lhs >> 32) * (rhs & 0xFFFFFFFF);
30+
uint64_t lo_hi = (lhs & 0xFFFFFFFF) * (rhs >> 32);
31+
uint64_t hi_hi = (lhs >> 32) * (rhs >> 32);
32+
uint64_t cross = ((lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi);
33+
return (u128){
34+
.hi = ((hi_lo >> 32) + (cross >> 32) + hi_hi),
35+
.lo = ((cross << 32) | (lo_lo & 0xFFFFFFFF)),
36+
};
37+
}
38+
39+
/* From https://stackoverflow.com/a/70052545 */
40+
41+
/* clang-format off */
42+
43+
#define SUBCcc(a,b,cy,t0,t1,t2) \
44+
(t0=(b)+cy, t1=(a), cy=t0<cy, t2=t1<t0, cy=cy+t2, t1-t0)
45+
46+
#define SUBcc(a,b,cy,t0,t1) \
47+
(t0=(b), t1=(a), cy=t1<t0, t1-t0)
48+
49+
#define SUBC(a,b,cy,t0,t1) \
50+
(t0=(b)+cy, t1=(a), t1-t0)
51+
52+
#define ADDCcc(a,b,cy,t0,t1) \
53+
(t0=(b)+cy, t1=(a), cy=t0<cy, t0=t0+t1, t1=t0<t1, cy=cy+t1, t0=t0)
54+
55+
#define ADDcc(a,b,cy,t0,t1) \
56+
(t0=(b), t1=(a), t0=t0+t1, cy=t0<t1, t0=t0)
57+
58+
#define ADDC(a,b,cy,t0,t1) \
59+
(t0=(b)+cy, t1=(a), t0+t1)
60+
61+
/* clang-format on */
62+
63+
u128 u128_divide(u128 dvnd, u128 dvsr)
64+
{
65+
u128 quot, rem, tmp;
66+
uint64_t cy, t0, t1, t2;
67+
68+
quot.hi = dvnd.hi;
69+
quot.lo = dvnd.lo;
70+
rem.hi = 0;
71+
rem.lo = 0;
72+
73+
for (int i = 0; i < 128; i++) {
74+
quot.lo = ADDcc(quot.lo, quot.lo, cy, t0, t1);
75+
quot.hi = ADDCcc(quot.hi, quot.hi, cy, t0, t1);
76+
rem.lo = ADDCcc(rem.lo, rem.lo, cy, t0, t1);
77+
rem.hi = ADDC(rem.hi, rem.hi, cy, t0, t1);
78+
tmp.lo = SUBcc(rem.lo, dvsr.lo, cy, t0, t1);
79+
tmp.hi = SUBCcc(rem.hi, dvsr.hi, cy, t0, t1, t2);
80+
if (!cy) { // remainder >= divisor
81+
rem.lo = tmp.lo;
82+
rem.hi = tmp.hi;
83+
quot.lo |= 1;
84+
}
85+
}
86+
87+
return quot;
88+
}

firmware/common/u128.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2026 Great Scott Gadgets <info@greatscottgadgets.com>
3+
*
4+
* This file is part of HackRF.
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2, or (at your option)
9+
* any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; see the file COPYING. If not, write to
18+
* the Free Software Foundation, Inc., 51 Franklin Street,
19+
* Boston, MA 02110-1301, USA.
20+
*/
21+
22+
#pragma once
23+
24+
#include <stdint.h>
25+
26+
typedef struct {
27+
uint64_t hi;
28+
uint64_t lo;
29+
} u128;
30+
31+
u128 u128_multiply(uint64_t a, uint64_t b);
32+
u128 u128_divide(u128 dvnd, u128 dvsr);

firmware/hackrf-common.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ macro(DeclareTargets)
203203
${PATH_HACKRF_FIRMWARE_COMMON}/adc.c
204204
${PATH_HACKRF_FIRMWARE_COMMON}/da7219.c
205205
${PATH_HACKRF_FIRMWARE_COMMON}/max283x.c
206+
${PATH_HACKRF_FIRMWARE_COMMON}/u128.c
206207
)
207208

208209
if(BOARD STREQUAL "RAD1O")

0 commit comments

Comments
 (0)