```   1 ------------------------------------------------------------------------------
2 ------------------------------------------------------------------------------
3 -- This file is part of 'Finite Field Arithmetic', aka 'FFA'.               --
4 --                                                                          --
5 -- (C) 2017 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 --                                                                          --
17 ------------------------------------------------------------------------------
18 ------------------------------------------------------------------------------
19
20 with Word_Ops; use Word_Ops;
21
22
23 -- Fundamental Arithmetic operators on FZ:
24 package body FZ_Arith is
25
26    -- Destructive Add: X := X + Y; Overflow := Carry; optional OF_In
27    procedure FZ_Add_D(X          : in out FZ;
28                       Y          : in     FZ;
29                       Overflow   : out    WBool;
30                       OF_In      : in     WBool := 0) is
31       Carry : WBool := OF_In;
32    begin
33       for i in 0 .. Word_Index(X'Length - 1) loop
34          declare
35             A : constant Word := X(X'First + i);
36             B : constant Word := Y(Y'First + i);
37             S : constant Word := A + B + Carry;
38          begin
39             X(X'First + i) := S;
40             Carry          := W_Carry(A, B, S);
41          end;
42       end loop;
43       Overflow := Carry;
45
46
47    -- Destructive Add: X := X + W; Overflow := Carry
48    procedure FZ_Add_D_W(X        : in out FZ;
49                         W        : in     Word;
50                         Overflow : out    WBool) is
51       Carry : Word := W;
52    begin
53       for i in X'Range loop
54          declare
55             A : constant Word := X(I);
56             S : constant Word := A + Carry;
57          begin
58             X(i)  := S;
59             Carry := W_Carry(A, 0, S);
60          end;
61       end loop;
62       Overflow := Carry;
64
65
66    -- Sum := X + Y; Overflow := Carry
67    procedure FZ_Add(X          : in  FZ;
68                     Y          : in  FZ;
69                     Sum        : out FZ;
70                     Overflow   : out WBool) is
71       Carry : WBool := 0;
72    begin
73       for i in 0 .. Word_Index(X'Length - 1) loop
74          declare
75             A : constant Word := X(X'First + i);
76             B : constant Word := Y(Y'First + i);
77             S : constant Word := A + B + Carry;
78          begin
79             Sum(Sum'First + i) := S;
80             Carry  := W_Carry(A, B, S);
81          end;
82       end loop;
83       Overflow := Carry;
85
86
87    -- Gate = 1: Sum := X + Y; Overflow := Carry
88    -- Gate = 0: Sum := X;     Overflow := 0
89    procedure FZ_Add_Gated_O(X          : in  FZ;
90                             Y          : in  FZ;
91                             Gate       : in  WBool;
92                             Sum        : out FZ;
93                             Overflow   : out WBool) is
94       Carry : WBool := 0;
95       Mask  : constant Word := 0 - Gate;
96    begin
97       for i in 0 .. Word_Index(X'Length - 1) loop
98          declare
99             A : constant Word := X(X'First + i);
100             B : constant Word := Y(Y'First + i) and Mask;
101             S : constant Word := A + B + Carry;
102          begin
103             Sum(Sum'First + i) := S;
104             Carry  := W_Carry(A, B, S);
105          end;
106       end loop;
107       Overflow := Carry;
109
110
111    -- Same as FZ_Add_Gated_O, but without Overflow output
112    procedure FZ_Add_Gated(X          : in  FZ;
113                           Y          : in  FZ;
114                           Gate       : in  WBool;
115                           Sum        : out FZ) is
116       Overflow : Word;
117       pragma Unreferenced(Overflow);
118    begin
119       FZ_Add_Gated_O(X, Y, Gate, Sum, Overflow);
121
122
123    -- Destructive Sub: X := X - Y; Underflow := Borrow
124    procedure FZ_Sub_D(X          : in out FZ;
125                       Y          : in     FZ;
126                       Underflow  : out    WBool) is
127       Borrow : WBool := 0;
128    begin
129       for i in 0 .. Word_Index(X'Length - 1) loop
130          declare
131             A : constant Word := X(X'First + i);
132             B : constant Word := Y(Y'First + i);
133             S : constant Word := A - B - Borrow;
134          begin
135             X(X'First + i) := S;
136             Borrow         := W_Borrow(A, B, S);
137          end;
138       end loop;
139       Underflow := Borrow;
140    end FZ_Sub_D;
141
142
143    -- Difference := X - Y; Underflow := Borrow
144    procedure FZ_Sub(X          : in  FZ;
145                     Y          : in  FZ;
146                     Difference : out FZ;
147                     Underflow  : out WBool) is
148       Borrow : WBool := 0;
149    begin
150       for i in 0 .. Word_Index(X'Length - 1) loop
151          declare
152             A : constant Word := X(X'First + i);
153             B : constant Word := Y(Y'First + i);
154             S : constant Word := A - B - Borrow;
155          begin
156             Difference(Difference'First + i) := S;
157             Borrow := W_Borrow(A, B, S);
158          end;
159       end loop;
160       Underflow := Borrow;
161    end FZ_Sub;
162
163
164    -- Destructive: If Cond is 1, NotN := ~N; otherwise NotN := N.
165    procedure FZ_Not_Cond_D(N    : in out FZ;
166                            Cond : in     WBool)is
167
169       Inv : constant Word := 0 - Cond;
170
171    begin
172
173       for i in N'Range loop
174
175          -- Invert (or, if Cond is 0, do nothing)
176          N(i) := N(i) xor Inv;
177
178       end loop;
179
180    end FZ_Not_Cond_D;
181
182
183    -- Subtractor that gets absolute value if underflowed, in const. time
184    procedure FZ_Sub_Abs(X          : in FZ;
185                         Y          : in FZ;
186                         Difference : out FZ;
187                         Underflow  : out WBool) is
188
189       O : Word := 0;
190       pragma Unreferenced(O);
191
192    begin
193
194       -- First, we subtract normally
195       FZ_Sub(X, Y, Difference, Underflow);
196
197       -- If borrow - negate,
198       FZ_Not_Cond_D(Difference, Underflow);
199
200       -- ... and also increment.