File : fz_lomul.adb
1 ------------------------------------------------------------------------------
2 ------------------------------------------------------------------------------
3 -- This file is part of 'Finite Field Arithmetic', aka 'FFA'. --
4 -- --
5 -- (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) --
6 -- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html --
7 -- --
8 -- You do not have, nor can you ever acquire the right to use, copy or --
9 -- distribute this software ; Should you use this software for any purpose, --
10 -- or copy and distribute it to anyone or in any manner, you are breaking --
11 -- the laws of whatever soi-disant jurisdiction, and you promise to --
12 -- continue doing so for the indefinite future. In any case, please --
13 -- always : read and understand any software ; verify any PGP signatures --
14 -- that you use - for any purpose. --
15 -- --
16 -- See also http://trilema.com/2015/a-new-software-licensing-paradigm . --
17 ------------------------------------------------------------------------------
18 ------------------------------------------------------------------------------
19
20 with Words; use Words;
21 with Word_Ops; use Word_Ops;
22 with W_Mul; use W_Mul;
23 with FZ_Arith; use FZ_Arith;
24 with FZ_Mul; use FZ_Mul;
25
26
27 -- "Low Multiplication" computes only the bottom half of the product XY.
28 -- Presently, it is used solely in Barrett's Modular Reduction.
29
30 package body FZ_LoMul is
31
32 -- Low-Only Comba's multiplier. (CAUTION: UNBUFFERED)
33 procedure FZ_Low_Mul_Comba(X : in FZ;
34 Y : in FZ;
35 XY : out FZ) is
36
37 -- Words in each multiplicand (and also in the half-product)
38 L : constant Word_Index := X'Length;
39
40 -- 3-word Accumulator
41 A2, A1, A0 : Word := 0;
42
43 begin
44
45 -- Compute the lower half of the Product, which is all we want:
46 for N in 0 .. L - 1 loop
47
48 -- Compute the Nth (indexed from zero) column of the Half-Product
49 declare
50
51 -- The outputs of a Word multiplication
52 Lo, Hi : Word;
53
54 -- Carry for the Accumulator addition
55 C : WBool;
56
57 -- Sum for Accumulator addition
58 Sum : Word;
59
60 begin
61
62 -- For lower half of XY, will go from 0 to N
63 -- For upper half of XY, will go from N - L + 1 to L - 1
64 for j in 0 .. N loop
65
66 -- Hi:Lo := j-th Word of X * (N - j)-th Word of Y
67 Mul_Word(X(X'First + j),
68 Y(Y'First - j + N),
69 Lo, Hi);
70
71 -- Now add Hi:Lo into the Accumulator:
72
73 -- A0 += Lo; C := Carry
74 Sum := A0 + Lo;
75 C := W_Carry(A0, Lo, Sum);
76 A0 := Sum;
77
78 -- A1 += Hi + C; C := Carry
79 Sum := A1 + Hi + C;
80 C := W_Carry(A1, Hi, Sum);
81 A1 := Sum;
82
83 -- A2 += A2 + C
84 A2 := A2 + C;
85
86 end loop;
87
88 -- We now have the Nth (indexed from zero) word of XY
89 XY(XY'First + N) := A0;
90
91 -- Right-Shift the Accumulator by one Word width:
92 A0 := A1;
93 A1 := A2;
94 A2 := 0;
95 end;
96
97 end loop;
98
99 end FZ_Low_Mul_Comba;
100
101
102 -- Low-Only Multiplier. (CAUTION: UNBUFFERED)
103 procedure Low_Mul(X : in FZ;
104 Y : in FZ;
105 XY : out FZ) is
106
107 -- L is the wordness of a multiplicand. Guaranteed to be a power of two.
108 L : constant Word_Count := X'Length;
109
110 -- K is HALF of the length of a multiplicand.
111 K : constant Word_Index := L / 2;
112
113 -- A 'KSeg' is the same length as HALF of a multiplicand.
114 subtype KSeg is FZ(1 .. K);
115
116 -- The two K-sized variables of the half-product equation:
117 LH, HL : KSeg;
118
119 -- Bottom and Top K-sized halves of the multiplicand X.
120 XLo : KSeg renames X( X'First .. X'Last - K );
121 XHi : KSeg renames X( X'First + K .. X'Last );
122
123 -- Bottom and Top K-sized halves of the multiplicand Y.
124 YLo : KSeg renames Y( Y'First .. Y'Last - K );
125 YHi : KSeg renames Y( Y'First + K .. Y'Last );
126
127 -- Top K-sized half of the half-product XY.
128 XYHi : KSeg renames XY( XY'First + K .. XY'Last );
129
130 -- Carry from individual term additions.
131 C : WBool;
132 pragma Unreferenced(C);
133
134 begin
135
136 -- Recurse to FULL-width multiplication: XY := XLo * YLo
137 FZ_Multiply_Unbuffered(XLo, YLo, XY);
138
139 -- Recurse to HALF-width multiplication: LH := XLo * YHi
140 FZ_Low_Multiply_Unbuffered(XLo, YHi, LH);
141
142 -- Recurse to HALF-width multiplication: HL := XHi * YLo
143 FZ_Low_Multiply_Unbuffered(XHi, YLo, HL);
144
145 -- XY += 2^(K * Bitness) * LH
146 FZ_Add_D(X => XYHi, Y => LH, Overflow => C);
147
148 -- XY += 2^(K * Bitness) * HL
149 FZ_Add_D(X => XYHi, Y => HL, Overflow => C);
150
151 end Low_Mul;
152 -- CAUTION: Inlining prohibited for Low_Mul !
153
154
155 -- Low-Only Multiplier. (CAUTION: UNBUFFERED)
156 procedure FZ_Low_Multiply_Unbuffered(X : in FZ;
157 Y : in FZ;
158 XY : out FZ) is
159
160 -- The length of either multiplicand
161 L : constant Word_Count := X'Length;
162
163 begin
164
165 if L <= Low_Mul_Thresh then
166
167 -- Base case:
168 FZ_Low_Mul_Comba(X, Y, XY);
169
170 else
171
172 -- Recursive case:
173 Low_Mul(X, Y, XY);
174
175 end if;
176
177 end FZ_Low_Multiply_Unbuffered;
178
179
180 -- Low-Only Multiplier. Preserves the inputs.
181 procedure FZ_Low_Multiply_Buffered(X : in FZ;
182 Y : in FZ;
183 XY : out FZ) is
184
185 -- Product buffer.
186 P : FZ(1 .. X'Length);
187
188 begin
189
190 FZ_Low_Multiply_Unbuffered(X, Y, P);
191
192 XY := P;
193
194 end FZ_Low_Multiply_Buffered;
195
196 end FZ_LoMul;