File : fz_arith.adb


   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 --                                                                          --
  16 -- See also http://trilema.com/2015/a-new-software-licensing-paradigm .     --
  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;
  44    end FZ_Add_D;
  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;
  63    end FZ_Add_D_W;
  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;
  84    end FZ_Add;
  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;
 108    end FZ_Add_Gated_O;
 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);
 120    end FZ_Add_Gated;
 121    
 122    
 123    -- Difference := X - Y; Underflow := Borrow
 124    procedure FZ_Sub(X          : in  FZ;
 125                     Y          : in  FZ;
 126                     Difference : out FZ;
 127                     Underflow  : out WBool) is
 128       Borrow : WBool := 0;
 129    begin
 130       for i in 0 .. Word_Index(X'Length - 1) loop
 131          declare
 132             A : constant Word := X(X'First + i);
 133             B : constant Word := Y(Y'First + i);
 134             S : constant Word := A - B - Borrow;
 135          begin
 136             Difference(Difference'First + i) := S;
 137             Borrow := W_Borrow(A, B, S);
 138          end;
 139       end loop;
 140       Underflow := Borrow;
 141    end FZ_Sub;
 142    
 143    
 144    -- Destructive: If Cond is 1, NotN := ~N; otherwise NotN := N.
 145    procedure FZ_Not_Cond_D(N    : in out FZ;
 146                            Cond : in     WBool)is
 147       
 148       -- The inversion mask
 149       Inv : constant Word := 0 - Cond;
 150       
 151    begin
 152       
 153       for i in N'Range loop
 154          
 155          -- Invert (or, if Cond is 0, do nothing)
 156          N(i) := N(i) xor Inv;
 157          
 158       end loop;
 159       
 160    end FZ_Not_Cond_D;
 161    
 162    
 163    -- Subtractor that gets absolute value if underflowed, in const. time
 164    procedure FZ_Sub_Abs(X          : in FZ;
 165                         Y          : in FZ;
 166                         Difference : out FZ;
 167                         Underflow  : out WBool) is
 168       
 169       O : Word := 0;
 170       pragma Unreferenced(O);
 171       
 172    begin
 173       
 174       -- First, we subtract normally
 175       FZ_Sub(X, Y, Difference, Underflow);
 176       
 177       -- If borrow - negate,
 178       FZ_Not_Cond_D(Difference, Underflow);
 179       
 180       -- ... and also increment.
 181       FZ_Add_D_W(Difference, Underflow, O);
 182       
 183    end FZ_Sub_Abs;
 184    
 185    
 186 end FZ_Arith;