tfhe_hpu_backend/asm/dop/
mod.rs

1pub mod arg;
2mod dop_macro;
3pub mod field;
4pub mod fmt;
5mod opcode;
6pub mod pbs_macro;
7
8use lazy_static::lazy_static;
9use std::collections::HashMap;
10
11use crate::{dop, impl_dop, impl_dop_parser};
12pub use arg::{FromAsm, IsFlush, ParsingError, ToAsm, ToFlush};
13pub use field::{
14    ImmId, MemId, MulFactor, PbsGid, PeArithInsn, PeArithMsgInsn, PeMemInsn, PePbsInsn, PeSyncInsn,
15    RegId, SyncId,
16};
17pub use fmt::{
18    DOpRawHex, DOpRepr, PeArithHex, PeArithMsgHex, PeMemHex, PePbsHex, PeSyncHex, ToHex,
19};
20pub use opcode::{DOpType, Opcode};
21
22dop!(
23    // Arith operation
24    ["ADD", opcode::Opcode::ADD(), PeArithInsn],
25    ["SUB", opcode::Opcode::SUB(), PeArithInsn],
26    ["MAC", opcode::Opcode::MAC(), PeArithInsn{mul_factor}],
27
28    // ArithMsg operation
29    ["ADDS", opcode::Opcode::ADDS(), PeArithMsgInsn],
30    ["SUBS", opcode::Opcode::SUBS(), PeArithMsgInsn],
31    ["SSUB", opcode::Opcode::SSUB(), PeArithMsgInsn],
32    ["MULS", opcode::Opcode::MULS(), PeArithMsgInsn],
33
34    // Ld/st operation
35    ["LD", opcode::Opcode::LD(), PeMemInsn{ld}],
36    ["ST", opcode::Opcode::ST(), PeMemInsn{st}]
37
38    // Pbs operation
39    ["PBS", opcode::Opcode::PBS(1), PePbsInsn, "_F"],
40    ["PBS_ML2", opcode::Opcode::PBS(2), PePbsInsn, "_F"],
41    ["PBS_ML4", opcode::Opcode::PBS(4), PePbsInsn, "_F"],
42    ["PBS_ML8", opcode::Opcode::PBS(8), PePbsInsn, "_F"],
43
44    // Pbs flush operation
45    ["PBS_F", opcode::Opcode::PBS_F(1), PePbsInsn],
46    ["PBS_ML2_F", opcode::Opcode::PBS_F(2), PePbsInsn],
47    ["PBS_ML4_F", opcode::Opcode::PBS_F(4), PePbsInsn],
48    ["PBS_ML8_F", opcode::Opcode::PBS_F(8), PePbsInsn],
49
50    // Sync operation
51    ["SYNC", opcode::Opcode::SYNC(), PeSyncInsn],
52);
53
54#[derive(Debug, Clone, Copy)]
55pub struct DigitParameters {
56    pub msg_w: usize,
57    pub carry_w: usize,
58}
59
60impl DigitParameters {
61    /// Msg field only
62    pub fn msg_mask(&self) -> usize {
63        (1 << self.msg_w) - 1
64    }
65    /// Carry field only
66    pub fn carry_mask(&self) -> usize {
67        ((1 << (self.carry_w)) - 1) << self.msg_w
68    }
69    /// Padding bit only
70    pub fn padding_mask(&self) -> usize {
71        1 << (self.carry_w + self.msg_w)
72    }
73
74    /// carry + msg fields only
75    pub fn data_mask(&self) -> usize {
76        self.carry_mask() | self.msg_mask()
77    }
78    /// Padding + carry + msg fields
79    pub fn raw_mask(&self) -> usize {
80        self.padding_mask() | self.data_mask()
81    }
82
83    /// Message range (used for neg operation)
84    pub fn msg_range(&self) -> usize {
85        1 << self.msg_w
86    }
87
88    /// Compute available linear operation based on carry_w/msg_w
89    // TODO: Find a proper way to have nu < carry_w (i.e ManyLutPbs case)
90    pub fn nu(&self) -> usize {
91        (self.carry_mask() + self.msg_mask()) / self.msg_mask()
92    }
93
94    pub fn total_width(&self) -> usize {
95        self.msg_w + self.carry_w
96    }
97}
98
99/// Base trait to depict an Pbs function
100/// Provides a set of method to reason about pbs
101#[enum_dispatch]
102pub trait PbsLut {
103    fn name(&self) -> &'static str;
104    fn gid(&self) -> PbsGid;
105    fn lut_nb(&self) -> u8;
106    fn lut_lg(&self) -> u8;
107    fn fn_at(&self, pos: usize, params: &DigitParameters, val: usize) -> usize;
108    fn deg_at(&self, pos: usize, params: &DigitParameters, deg: usize) -> usize;
109    // Blanket implementation
110    fn lut_msk(&self) -> usize {
111        usize::MAX << self.lut_lg()
112    }
113}
114
115use crate::{impl_pbs, pbs};
116use enum_dispatch::enum_dispatch;
117use pbs_macro::{CMP_EQUAL, CMP_INFERIOR, CMP_SUPERIOR};
118
119pbs!(
120["None" => 0 [
121    @0 =>{
122        |_params: &DigitParameters, val | val;
123        |_params: &DigitParameters, deg| deg;
124    }
125]],
126["MsgOnly" => 1 [
127    @0 =>{
128        |params: &DigitParameters, val | val & params.msg_mask();
129        |params: &DigitParameters, _deg| params.msg_mask();
130    }
131]],
132["CarryOnly" => 2 [
133    @0 =>{
134        |params: &DigitParameters, val | val & params.carry_mask();
135        |params: &DigitParameters, _deg| params.carry_mask();
136    }
137]],
138["CarryInMsg" => 3 [
139    @0 =>{
140        |params: &DigitParameters, val | (val & params.carry_mask()) >> params.msg_w;
141        |params: &DigitParameters, _deg| params.msg_mask();
142    }
143]]
144["MultCarryMsg" => 4 [
145    @0 =>{
146        |params: &DigitParameters, val | (((val & params.carry_mask()) >> params.msg_w) * (val & params.msg_mask())) & params.data_mask();
147        |params: &DigitParameters, _deg| params.data_mask();
148    }
149]],
150["MultCarryMsgLsb" => 5 [
151    @0 =>{
152        |params: &DigitParameters, val | (((val & params.carry_mask()) >> params.msg_w) * (val & params.msg_mask())) & params.msg_mask();
153        |params: &DigitParameters, _deg| params.msg_mask();
154    },
155]],
156["MultCarryMsgMsb" => 6 [
157    @0 =>{
158        |params: &DigitParameters, val | ((((val & params.carry_mask()) >> params.msg_w) * (val & params.msg_mask())) >> params.msg_w) & params.msg_mask();
159        |params: &DigitParameters, _deg| params.msg_mask();
160    }
161]],
162["BwAnd" => 7 [
163    @0 =>{
164        |params: &DigitParameters, val | (((val & params.carry_mask()) >> params.msg_w) & (val & params.msg_mask())) & params.msg_mask();
165        |params: &DigitParameters, _deg| params.msg_mask();
166    }
167]],
168["BwOr" => 8 [
169    @0 =>{
170        |params: &DigitParameters, val | (((val & params.carry_mask()) >> params.msg_w) | (val & params.msg_mask())) & params.msg_mask();
171        |params: &DigitParameters, _deg| params.msg_mask();
172    }
173]],
174["BwXor" => 9 [
175    @0 =>{
176        |params: &DigitParameters, val | (((val & params.carry_mask()) >> params.msg_w) ^ (val & params.msg_mask())) & params.msg_mask();
177        |params: &DigitParameters, _deg| params.msg_mask();
178    }
179]],
180
181["CmpSign" => 10 [
182    @0 =>{
183        |_params: &DigitParameters, val | {
184            // Signed comparison with 0. Based on behavior of negacyclic function.
185            // Example for Padding| 4bit digits (i.e 2msg2Carry)
186            // 1|xxxx -> SignLut -> -1 -> 0|1111
187            // x|0000 -> SignLut ->  0 -> 0|0000
188            // 0|xxxx -> SignLut ->  1 -> 0|0001
189            if val != 0 {1} else {0}
190        };
191        // WARN: in practice return value with padding that could encode -1, 0, 1
192        //       But should always be follow by an add to reach back range 0, 1, 2
193        //       To ease degree handling considered an output degree of 1 to obtain
194        //       degree 2 after add
195        // Not a perfect solution but the easiest to prevent degree error
196        |_params: &DigitParameters, _deg| 1;
197    }
198]],
199["CmpReduce" => 11 [
200    @0 =>{
201        |params: &DigitParameters, val | {
202            // Carry contain MSB cmp result, msg LSB cmp result
203            // Reduction is made from lsb to msb as follow
204            // MSB      | LSB | Out
205            // Inferior | x   | Inferior
206            // Equal    | x   | x
207            // Superior | x   | Superior
208            let carry_field = (val & params.carry_mask()) >> params.msg_w;
209            let msg_field = val & params.msg_mask();
210
211            match (carry_field, msg_field) {
212                (CMP_EQUAL, lsb_cmp) => lsb_cmp,
213                _ => carry_field
214            }
215        };
216        |_params: &DigitParameters, _deg| 2;
217    }
218]]
219
220["CmpGt" => 12 [
221    @0 =>{
222        |params: &DigitParameters, val | match val & params.msg_mask() {
223            CMP_SUPERIOR => 1,
224            _ => 0,
225        };
226        |_params: &DigitParameters, _deg| 1;
227    }
228]],
229["CmpGte" => 13 [
230    @0 =>{
231        |params: &DigitParameters, val | match val & params.msg_mask() {
232            CMP_SUPERIOR | CMP_EQUAL => 1,
233            _ => 0,
234        };
235        |_params: &DigitParameters, _deg| 1;
236    }
237]],
238// Could be merge with Gt/Gte
239["CmpLt" => 14 [
240    @0 =>{
241        |params: &DigitParameters, val | match val & params.msg_mask() {
242            CMP_INFERIOR => 1,
243            _ => 0,
244        };
245        |_params: &DigitParameters, _deg| 1;
246    }
247]],
248["CmpLte" => 15 [
249    @0 =>{
250        |params: &DigitParameters, val | match val & params.msg_mask() {
251            CMP_INFERIOR | CMP_EQUAL => 1,
252            _ => 0,
253        };
254        |_params: &DigitParameters, _deg| 1;
255    }
256]],
257["CmpEq" => 16 [
258    @0 =>{
259        |params: &DigitParameters, val | match val & params.msg_mask() {
260            CMP_EQUAL => 1,
261            _ => 0,
262        };
263        |_params: &DigitParameters, _deg| 1;
264    }
265]],
266["CmpNeq" => 17 [
267    @0 =>{
268        |params: &DigitParameters, val | match val & params.msg_mask() {
269            CMP_EQUAL => 0,
270            _ => 1,
271        };
272        |_params: &DigitParameters, _deg| 1;
273    }
274]],
275["ManyGenProp" => 18 [ // Turns carry save into a generate/propagate pair and message with manyLUT
276    @0 =>{
277        |params: &DigitParameters, val| {
278               ((val & params.carry_mask()) >> (params.msg_w)) << 1|       // Generate
279               (((val & params.msg_mask()) == params.msg_mask()) as usize) // Propagate
280           };
281        |_params: &DigitParameters, _deg| 3;
282    },
283    @1 =>{
284        |params: &DigitParameters, val| { val & params.msg_mask()};
285        |params: &DigitParameters, _deg| params.msg_mask();
286    }
287]],
288["ReduceCarry2" => 19 [ // Reduces a carry propagation add to two bits from an
289                        // input in which the carry is in the second bit.
290    @0 =>{
291        |_params: &DigitParameters, val | {
292            let carry = val >> 2;
293            let prop = (val & 3 == 3) as usize;
294            (carry << 1) | prop
295       };
296        |_params: &DigitParameters, _deg| 3;
297    }
298]],
299["ReduceCarry3" => 20 [ // Reduces a carry propagation add to two bits from an
300                        // input in which the carry is in the third bit.
301    @0 =>{
302        |_params: &DigitParameters, val | {
303            let carry = val >> 3;
304            let prop = (val & 7 == 7) as usize;
305            (carry << 1) | prop
306       };
307        |_params: &DigitParameters, _deg| 3;
308    }
309]],
310["ReduceCarryPad" => 21 [ // Reduces a carry propagation add to two bits from an
311                          // input in which the carry is in the padding bit.
312        // This corresponds to the accumulated propagation status
313        // of 4 consecutive blocks.
314        // !! The padding bit is used.
315        // +1 must be done after this PBS to retrieve the propagation status value.
316        // 0_1111 => 0_0000 + 1 => 1 Propagate
317        // 0_xxxx -> 1_1111 + 1 => 0 No carry
318        // 1_xxxx -> 0_0001 + 1 => 2 Generate
319    @0 =>{
320        |params: &DigitParameters, val | {
321            if val == params.data_mask() {
322                0
323            } else {
324                params.raw_mask()
325            }
326       };
327        |_params: &DigitParameters, _deg| 1;
328    }
329]],
330["GenPropAdd" => 22 [ // Adds a generate/propagate pair with a message modulus message
331    @0 =>{
332        |params: &DigitParameters, val | {
333           let lhs =  val & params.msg_mask();
334           let rhs = (val & params.carry_mask()) >> params.msg_w;
335           let rhs_gen = rhs >> 1;
336           (lhs + rhs_gen) & params.msg_mask()
337       };
338        |params: &DigitParameters, _deg| params.msg_mask();
339    }
340]],
341
342["IfTrueZeroed" => 23 [ // Ct must contain CondCt in Carry and ValueCt in Msg. If condition it's *TRUE*, value ct is forced to 0
343    @0 =>{
344        |params: &DigitParameters, val | {
345           let value =  val & params.msg_mask();
346           let cond = (val & params.carry_mask()) >> params.msg_w;
347           if cond != 0 {0} else {value}
348       };
349        |params: &DigitParameters, _deg| params.msg_mask();
350    }
351]],
352["IfFalseZeroed" => 24 [ // Ct must contain CondCt in Carry and ValueCt in Msg. If condition it's *FALSE*, value ct is forced to 0
353    @0 =>{
354        |params: &DigitParameters, val | {
355           let value =  val & params.msg_mask();
356           let cond = (val & params.carry_mask()) >> params.msg_w;
357           if cond != 0 {value} else {0}
358       };
359        |params: &DigitParameters, _deg| params.msg_mask();
360    }
361]],
362["Ripple2GenProp" => 25 [ // Converts from Ripple carry to GenProp
363    @0 =>{
364        |params: &DigitParameters, val | {
365           (val & params.msg_mask()) * 2
366       };
367        |params: &DigitParameters, _deg| params.msg_mask();
368    }
369]],
370
371// Below Pbs are defined for Test only
372["TestMany2" => 128 [
373    @0 =>{
374        |_params: &DigitParameters, val | val;
375        |params: &DigitParameters, _deg| params.msg_mask();
376    },
377    @1 =>{
378        |_params: &DigitParameters, val | val +1;
379        |params: &DigitParameters, _deg| params.msg_mask();
380    },
381]],
382["TestMany4" => 129 [
383    @0 =>{
384        |_params: &DigitParameters, val | val;
385        |params: &DigitParameters, _deg| params.msg_mask();
386    },
387    @1 =>{
388        |_params: &DigitParameters, val | val +1;
389        |params: &DigitParameters, _deg| params.msg_mask();
390    },
391    @2 =>{
392        |_params: &DigitParameters, val | val +2;
393        |params: &DigitParameters, _deg| params.msg_mask();
394    },
395    @3 =>{
396        |_params: &DigitParameters, val | val +3;
397        |params: &DigitParameters, _deg| params.msg_mask();
398    },
399]],
400["TestMany8" => 130 [
401    @0 =>{
402        |_params: &DigitParameters, val | val;
403        |params: &DigitParameters, _deg| params.msg_mask();
404    },
405    @1 =>{
406        |_params: &DigitParameters, val | val +1;
407        |params: &DigitParameters, _deg| params.msg_mask();
408    },
409    @2 =>{
410        |_params: &DigitParameters, val | val +2;
411        |params: &DigitParameters, _deg| params.msg_mask();
412    },
413    @3 =>{
414        |_params: &DigitParameters, val | val +3;
415        |params: &DigitParameters, _deg| params.msg_mask();
416    },
417    @4 =>{
418        |_params: &DigitParameters, val | val +4;
419        |params: &DigitParameters, _deg| params.msg_mask();
420    },
421    @5 =>{
422        |_params: &DigitParameters, val | val +5;
423        |params: &DigitParameters, _deg| params.msg_mask();
424    },
425    @6 =>{
426        |_params: &DigitParameters, val | val +6;
427        |params: &DigitParameters, _deg| params.msg_mask();
428    },
429    @7 =>{
430        |_params: &DigitParameters, val | val +7;
431        |params: &DigitParameters, _deg| params.msg_mask();
432    },
433]],
434["ManyCarryMsg" => 26 [ // Turns carry save into carry and message with manyLUT
435    @0 =>{
436        |params: &DigitParameters, val| { val & params.msg_mask()};
437        |params: &DigitParameters, _deg| params.msg_mask();
438    },
439    @1 =>{
440        |params: &DigitParameters, val| { val >> params.msg_w };
441        |params: &DigitParameters, _deg| (1 << (params.carry_w - 1)) - 1;
442    }
443]],
444["CmpGtMrg" => 27 [
445    @0 =>{
446        |params: &DigitParameters, val | {
447            let carry_field = (val & params.carry_mask()) >> params.msg_w;
448            let msg_field = val & params.msg_mask();
449
450            match (carry_field, msg_field) {
451                (CMP_SUPERIOR, _) |
452                (CMP_EQUAL, CMP_SUPERIOR) => 1,
453                _ => 0,
454            }
455        };
456        |_params: &DigitParameters, _deg| 1;
457    }
458]],
459["CmpGteMrg" => 28 [
460    @0 =>{
461        |params: &DigitParameters, val | {
462            let carry_field = (val & params.carry_mask()) >> params.msg_w;
463            let msg_field = val & params.msg_mask();
464
465            match (carry_field, msg_field) {
466                (CMP_SUPERIOR, _) |
467                (CMP_EQUAL, CMP_SUPERIOR) |
468                (CMP_EQUAL, CMP_EQUAL) => 1,
469                _ => 0,
470            }
471        };
472        |_params: &DigitParameters, _deg| 1;
473    }
474]],
475["CmpLtMrg" => 29 [
476    @0 =>{
477        |params: &DigitParameters, val | {
478            let carry_field = (val & params.carry_mask()) >> params.msg_w;
479            let msg_field = val & params.msg_mask();
480
481            match (carry_field, msg_field) {
482                (CMP_INFERIOR, _) |
483                (CMP_EQUAL, CMP_INFERIOR) => 1,
484                _ => 0,
485            }
486        };
487        |_params: &DigitParameters, _deg| 1;
488    }
489]],
490["CmpLteMrg" => 30 [
491    @0 =>{
492        |params: &DigitParameters, val | {
493            let carry_field = (val & params.carry_mask()) >> params.msg_w;
494            let msg_field = val & params.msg_mask();
495
496            match (carry_field, msg_field) {
497                (CMP_INFERIOR, _) |
498                (CMP_EQUAL, CMP_INFERIOR) |
499                (CMP_EQUAL, CMP_EQUAL) => 1,
500                _ => 0,
501            }
502        };
503        |_params: &DigitParameters, _deg| 1;
504    }
505]],
506["CmpEqMrg" => 31 [
507    @0 =>{
508        |params: &DigitParameters, val | {
509            let carry_field = (val & params.carry_mask()) >> params.msg_w;
510            let msg_field = val & params.msg_mask();
511
512            match (carry_field, msg_field) {
513                (CMP_EQUAL, CMP_EQUAL) => 1,
514                _ => 0,
515            }
516        };
517        |_params: &DigitParameters, _deg| 1;
518    }
519]],
520["CmpNeqMrg" => 32 [
521    @0 =>{
522        |params: &DigitParameters, val | {
523            let carry_field = (val & params.carry_mask()) >> params.msg_w;
524            let msg_field = val & params.msg_mask();
525
526            match (carry_field, msg_field) {
527                (CMP_EQUAL, CMP_EQUAL) => 0,
528                _ => 1,
529            }
530        };
531        |_params: &DigitParameters, _deg| 1;
532    }
533]],
534["IsSome" => 33 [
535    @0 =>{
536        |_params: &DigitParameters, val | {
537            if val != 0 { 1 } else { 0 }
538        };
539        |_params: &DigitParameters, _deg| 1;
540    }
541]],
542["CarryIsSome" => 34 [
543    @0 =>{
544        |params: &DigitParameters, val | {
545            let carry_field = (val & params.carry_mask()) >> params.msg_w;
546            if carry_field != 0 { 1 } else { 0 }
547        };
548        |_params: &DigitParameters, _deg| 1;
549    }
550]],
551["CarryIsNone" => 35 [
552    @0 =>{
553        |params: &DigitParameters, val | {
554            let carry_field = (val & params.carry_mask()) >> params.msg_w;
555            if carry_field == 0 { 1 } else { 0 }
556        };
557        |_params: &DigitParameters, _deg| 1;
558    }
559]],
560["MultCarryMsgIsSome" => 36 [
561    @0 =>{
562        |params: &DigitParameters, val | {
563            let carry_x_msg = (((val & params.carry_mask()) >> params.msg_w) * (val & params.msg_mask())) & params.data_mask();
564            if carry_x_msg != 0 { 1 } else { 0 }
565        };
566        |_params: &DigitParameters, _deg| 1;
567    }
568]],
569["MultCarryMsgMsbIsSome" => 37 [
570    @0 =>{
571        |params: &DigitParameters, val | {
572            let mul_msb = ((((val & params.carry_mask()) >> params.msg_w) * (val & params.msg_mask())) >> params.msg_w) & params.msg_mask();
573            if mul_msb != 0 { 1} else {0}
574        };
575        |params: &DigitParameters, _deg| params.msg_mask();
576    }
577]],
578["IsNull" => 38 [
579    @0 =>{
580        |params: &DigitParameters, val | {
581            let carry_field = (val & params.carry_mask()) >> params.msg_w;
582            let msg_field = val & params.msg_mask();
583
584            match (carry_field,msg_field) {
585                (0,0) => 1,
586                _ => 0,
587            }
588        };
589        |_params: &DigitParameters, _deg| 1;
590    }
591]],
592["IsNullPos1" => 39 [ // Output boolean at bit position 1 instead of 0
593    @0 =>{
594        |params: &DigitParameters, val | {
595            let carry_field = (val & params.carry_mask()) >> params.msg_w;
596            let msg_field = val & params.msg_mask();
597
598            match (carry_field,msg_field) {
599                (0,0) => 1 << 1,
600                _ => 0,
601            }
602        };
603        |_params: &DigitParameters, _deg| 1 << 1;
604    }
605]],
606["NotNull" => 40 [
607    @0 =>{
608        |params: &DigitParameters, val | {
609            let carry_field = (val & params.carry_mask()) >> params.msg_w;
610            let msg_field = val & params.msg_mask();
611
612            match (carry_field,msg_field) {
613                (0,0) => 0,
614                _ => 1,
615            }
616        };
617        |_params: &DigitParameters, _deg| 1;
618    }
619]],
620["MsgNotNull" => 41 [
621    @0 =>{
622        |params: &DigitParameters, val | {
623            let msg_field = val & params.msg_mask();
624
625            match msg_field {
626                0 => 0,
627                _ => 1,
628            }
629        };
630        |_params: &DigitParameters, _deg| 1;
631    }
632]],
633["MsgNotNullPos1" => 42 [ // Return the null (0) or not null (1)
634        // status of the msg part.
635        // Put the result at position 1.
636    @0 =>{
637        |params: &DigitParameters, val | {
638            let msg_field = val & params.msg_mask();
639
640            match msg_field {
641                0 => 0,
642                _ => 1 << 1,
643            }
644        };
645        |_params: &DigitParameters, _deg| 1 << 1;
646    }
647]],
648["ManyMsgSplitShift1" => 43 [ // Use manyLUT : split msg in halves, inverse their position
649        // in the message, and  output them separately.
650    @0 =>{
651        |params: &DigitParameters, val| {
652                let lsb_size = params.msg_w.div_ceil(2);
653                let msg_lsb = val & ((1 << lsb_size)-1);
654                msg_lsb << lsb_size
655        };
656        |params: &DigitParameters, _deg| {
657                let lsb_size = params.msg_w.div_ceil(2);
658                ((1 << lsb_size)-1) << lsb_size
659        };
660    },
661    @1 =>{
662        |params: &DigitParameters, val| {
663                let lsb_size = params.msg_w.div_ceil(2);
664                (val & params.msg_mask()) >> lsb_size // msg_msb
665        };
666        |params: &DigitParameters, _deg| {
667                let lsb_size = params.msg_w.div_ceil(2);
668                let msb_size = params.msg_w - lsb_size;
669                (1 << msb_size)-1
670        };
671    }
672]],
673["SolvePropGroupFinal0" => 44 [ // Solve the propagation status of
674        // of 4 blocks.
675        // The input contains the sum of the propagate status
676        // of (position + 1) blocks + the carry of previous group.
677        // The result depends on the position to solve. Here we solve position 0.
678        // The output value is then directly the carry.
679        // 1/0 + [0]
680        // 0x => NO_CARRY(0)
681        // 1x => GENERATE(1)
682    @0 =>{
683        |_params: &DigitParameters, val | {
684            let position = 0;
685            let pos_w = position + 2;
686            (val >> (pos_w-1)) & 1_usize // msb
687       };
688        |_params: &DigitParameters, _deg| 1;
689    }
690]],
691["SolvePropGroupFinal1" => 45 [ // Solve the propagation status of
692        // of 4 blocks.
693        // The input contains the sum of the propagate status
694        // of (position + 1) blocks + the carry of previous group.
695        // The result depends on the position to solve. Here we solve position 1.
696        // The output value is then directly the carry.
697        // 1/0 + + [0] + [1] << 1
698        // 0xx => NO_CARRY(0)
699        // 1xx => GENERATE(1)
700    @0 =>{
701        |_params: &DigitParameters, val | {
702            let position = 1;
703            let pos_w = position + 2;
704            (val >> (pos_w-1)) & 1_usize // msb
705       };
706        |_params: &DigitParameters, _deg| 1;
707    }
708]],
709["SolvePropGroupFinal2" => 46 [ // Solve the propagation status of
710        // of 4 blocks.
711        // The input contains the sum of the propagate status
712        // of (position + 1) blocks + the carry of previous group.
713        // The result depends on the position to solve. Here we solve position 2.
714        // The output value is then directly the carry.
715        // 1/0 + + [0] + [1] << 1 + [2] << 2
716        // 0xxx => NO_CARRY(0)
717        // 1xxx => GENERATE(1)
718    @0 =>{
719        |_params: &DigitParameters, val | {
720            let position = 2;
721            let pos_w = position + 2;
722            (val >> (pos_w-1)) & 1_usize // msb
723       };
724        |_params: &DigitParameters, _deg| 1;
725    }
726]],
727["ExtractPropGroup0" => 47 [ // Extract propagation status and
728        // set the value at the correct position location.
729        // Here the position is 0.
730    @0 =>{
731        |params: &DigitParameters, val | {
732            let position = 0;
733            let msg   = val & params.msg_mask();
734            let carry = (val >> params.msg_w) & 1_usize;
735            if carry == 1 {
736                2 << position // Generate
737            } else if msg == params.msg_mask() {
738                1 << position // Propagate
739            } else {
740                0 << position // No carry
741            }
742       };
743        |_params: &DigitParameters, _deg| {
744                let position = 0;
745                2 << position
746        };
747    }
748]],
749["ExtractPropGroup1" => 48 [ // Extract propagation status and
750        // set the value at the correct position location.
751        // Here the position is 1.
752    @0 =>{
753        |params: &DigitParameters, val | {
754            let position = 1;
755            let msg   = val & params.msg_mask();
756            let carry = (val >> params.msg_w) & 1_usize;
757            if carry == 1 {
758                2 << position // Generate
759            } else if msg == params.msg_mask() {
760                1 << position // Propagate
761            } else {
762                0 << position // No carry
763            }
764       };
765        |_params: &DigitParameters, _deg| {
766                let position = 1;
767                2 << position
768        };
769    }
770]],
771["ExtractPropGroup2" => 49 [ // Extract propagation status and
772        // set the value at the correct position location.
773        // Here the position is 2.
774    @0 =>{
775        |params: &DigitParameters, val | {
776            let position = 2;
777            let msg   = val & params.msg_mask();
778            let carry = (val >> params.msg_w) & 1_usize;
779            if carry == 1 {
780                2 << position // Generate
781            } else if msg == params.msg_mask() {
782                1 << position // Propagate
783            } else {
784                0 << position // No carry
785            }
786       };
787        |_params: &DigitParameters, _deg| {
788                let position = 2;
789                2 << position
790        };
791    }
792]],
793["ExtractPropGroup3" => 50 [ // Extract propagation status and
794        // set the value at the correct position location.
795        // Here the position is 3.
796    @0 =>{
797        |params: &DigitParameters, val | {
798            let position = 3;
799            let msg   = val & params.msg_mask();
800            let carry = (val >> params.msg_w) & 1_usize;
801            if carry == 1 {
802                2 << position // Generate
803            } else if msg == params.msg_mask() {
804                1 << position // Propagate
805            } else {
806                0 << position // No carry
807            }
808       };
809        |_params: &DigitParameters, _deg| {
810                let position = 3;
811                2 << position
812        };
813    }
814]],
815["SolveProp" => 51 [ // Solve the propagation status.
816        // 2 propagation status are stored in the input:
817        // MSB : propagation to solved
818        // LSB : neighbor's propagation
819    @0 =>{
820        |params: &DigitParameters, val | {
821            let msb = (val >> params.msg_w) & params.msg_mask();
822            let lsb = val & params.msg_mask();
823
824            if msb == 1 { // Propagate
825                lsb
826            } else {
827                msb
828            }
829       };
830        |_params: &DigitParameters, _deg| 2;
831    }
832]],
833["SolvePropCarry" => 52 [ // Solve the propagation status.
834        // A propagation status and a carry are stored in the input:
835        // Output a carry value.
836        // MSB : propagation to solved
837        // LSB : neighbor's carry bit
838    @0 =>{
839        |params: &DigitParameters, val | {
840            let msb = (val >> params.msg_w) & params.msg_mask();
841            let lsb = val & params.msg_mask();
842
843            if msb == 1 { // Propagate
844                lsb
845            } else {
846                msb >> 1 // Since generate equals 2. Here we want a carry output
847            }
848       };
849        |_params: &DigitParameters, _deg| 2;
850    }
851]],
852["SolveQuotient" => 53 [ // Solve the quotient of a division.
853        // The input contains the sum of 4 bits, representing the comparison of current remaining
854        // and the different multiples of the divider.
855        // Note that the values form a multi-hot. Therefore, their sum
856        // gives the value of the divider quotient, that corresponds to the remaining.
857        // 'b0000 => 3 (sum = 0)
858        // 'b1000 => 2 (sum = 1)
859        // 'b1100 => 1 (sum = 2)
860        // 'b1110 => 0 (sum = 3)
861    @0 =>{
862        |params: &DigitParameters, val | {
863            let v = val & params.data_mask();
864
865            match v {
866                0  => 3,
867                1  => 2,
868                2  => 1,
869                3  => 0,
870                _  => 0,
871                //_  => panic!("Unknown quotient value {}!",v) // should not end here
872            }
873       };
874        |_params: &DigitParameters, _deg| 3;
875    }
876]],
877["SolveQuotientPos1" => 54 [ // Solve the quotient of a division.
878        // The input contains the sum of 4 bits, representing the comparison of current remaining
879        // and the different multiples of the divider.
880        // Note that the comparison stored in position 1 instead of 0.
881        // Therefore the sum value is doubled.
882        // Note that the values form a multi-hot. Therefore, their sum
883        // gives the value of the divider quotient, that corresponds to the remaining.
884        // 'b0000 => 3 (sum = 0*2)
885        // 'b1000 => 2 (sum = 1*2)
886        // 'b1100 => 1 (sum = 2*2)
887        // 'b1110 => 0 (sum = 3*2)
888    @0 =>{
889        |params: &DigitParameters, val | {
890            let v = val & params.data_mask();
891
892            match v {
893                0  => 3,
894                2  => 2,
895                4  => 1,
896                6  => 0,
897                _  => 0,
898                //_  => panic!("Unknown quotient value {}!",v) // should not end here
899            }
900       };
901        |_params: &DigitParameters, _deg| 3;
902    }
903]],
904["IfPos1FalseZeroed" => 55 [ // Ct must contain CondCt in Carry bit 1 and ValueCt in Msg. If condition it's *FALSE*, value ct is forced to 0
905    @0 =>{
906        |params: &DigitParameters, val | {
907           let value =  val & params.msg_mask();
908           let cond = (val >> (params.msg_w + 1)) & 1;
909           if cond != 0 {value} else {0}
910       };
911        |params: &DigitParameters, _deg| params.msg_mask();
912    }
913]],
914["IfPos1FalseZeroedMsgCarry1" => 56 [ // Ct must contain CondCt in Carry bit 1
915        // and ValueCt in Msg + 1 carry bit. If condition it's *FALSE*, value ct is forced to 0
916    @0 =>{
917        |params: &DigitParameters, val | {
918           let value =  val & (params.msg_mask() * 2 + 1);
919           let cond = (val >> (params.msg_w + 1)) & 1;
920           if cond != 0 {value} else {0}
921       };
922        |params: &DigitParameters, _deg| params.msg_mask();
923    }
924]],
925
926// Shift related Pbs
927["ShiftLeftByCarryPos0Msg" => 57 [ // Ct must contain shift amount only bit 1 considered
928    @0 =>{
929        |params: &DigitParameters, val | {
930           let value =  val & params.msg_mask();
931           let shift = ((val & params.carry_mask()) >> params.msg_w) & 0x1;
932           (value << shift) & params.msg_mask()
933       };
934        |params: &DigitParameters, _deg| params.msg_mask();
935    }
936]],
937["ShiftLeftByCarryPos0MsgNext" => 58 [ // Ct must contain shift amount only bit 1 considered
938    @0 =>{
939        |params: &DigitParameters, val | {
940           let value =  val & params.msg_mask();
941           let shift = ((val & params.carry_mask()) >> params.msg_w) & 0x1;
942            ((value << shift) & params.carry_mask()) >> params.msg_w
943       };
944        |params: &DigitParameters, _deg| params.msg_mask();
945    }
946]],
947
948["ShiftRightByCarryPos0Msg" => 59 [ // Ct must contain shift amount only bit 1 considered
949    @0 =>{
950        |params: &DigitParameters, val | {
951           let value =  val & params.msg_mask();
952           let shift = ((val & params.carry_mask()) >> params.msg_w) & 0x1;
953           (value >> shift) & params.msg_mask()
954       };
955        |params: &DigitParameters, _deg| params.msg_mask();
956    }
957]],
958["ShiftRightByCarryPos0MsgNext" => 60 [ // Ct must contain shift amount only bit 1 considered
959    // NB: MsgNext with right shift is the content of blk at the right position (i.e. LSB side)
960    @0 =>{
961        |params: &DigitParameters, val | {
962           let value =  val & params.msg_mask();
963           let shift = ((val & params.carry_mask()) >> params.msg_w) & 0x1;
964           ((value << params.msg_w) >> shift) & params.msg_mask()
965       };
966        |params: &DigitParameters, _deg| params.msg_mask();
967    }
968]],
969// If then zero with condition in Carry0 or Carry1
970["IfPos0TrueZeroed" => 61 [ // Ct must contain CondCt in Carry[0] and ValueCt in Msg. If condition it's *TRUE*, value ct is forced to 0
971    @0 =>{
972        |params: &DigitParameters, val | {
973           let value =  val & params.msg_mask();
974           let cond = ((val & params.carry_mask()) >> params.msg_w) & 0x1;
975           if cond != 0 {0} else {value}
976       };
977        |params: &DigitParameters, _deg| params.msg_mask();
978    }
979]],
980["IfPos0FalseZeroed" => 62 [ // Ct must contain CondCt in Carry[0] and ValueCt in Msg. If condition it's *FALSE*, value ct is forced to 0
981    @0 =>{
982        |params: &DigitParameters, val | {
983           let value =  val & params.msg_mask();
984           let cond = ((val & params.carry_mask()) >> params.msg_w) & 0x1;
985           if cond != 0 {value} else {0}
986       };
987        |params: &DigitParameters, _deg| params.msg_mask();
988    }
989]],
990// If then zero with condition in Carry0 or Carry1
991["IfPos1TrueZeroed" => 63 [ // Ct must contain CondCt in Carry[1] and ValueCt in Msg. If condition it's *TRUE*, value ct is forced to 0
992    @0 =>{
993        |params: &DigitParameters, val | {
994           let value =  val & params.msg_mask();
995           let cond = ((val & params.carry_mask()) >> params.msg_w) & 0x2;
996           if cond != 0 {0} else {value}
997       };
998        |params: &DigitParameters, _deg| params.msg_mask();
999    }
1000]],
1001// NB: Lut IfPos1FalseZeroed already defined earlier
1002["ManyInv1CarryMsg" => 64 [ // Proceed Inv - ct
1003        // Extract message and carry using many LUT.
1004    @0 =>{
1005        |params: &DigitParameters, val | {
1006            let inv = 1;
1007            let mut value =  val & params.data_mask();
1008            if value > inv {
1009                0
1010            } else {
1011                value = inv - value;
1012                value & params.msg_mask()
1013            }
1014       };
1015        |params: &DigitParameters, _deg| params.msg_mask();
1016    },
1017    @1 =>{
1018        |params: &DigitParameters, val | {
1019            let inv = 1;
1020            let mut value =  val & params.data_mask();
1021            if value > inv {
1022                0
1023            } else {
1024                value = inv - value;
1025                value >> params.msg_w
1026            }
1027       };
1028        |_params: &DigitParameters, _deg| 1;
1029    },
1030]],
1031["ManyInv2CarryMsg" => 65 [ // Proceed Inv - ct
1032        // Extract message and carry using many LUT.
1033    @0 =>{
1034        |params: &DigitParameters, val | {
1035            let inv = 2;
1036            let mut value =  val & params.data_mask();
1037            if value > inv {
1038                0
1039            } else {
1040                value = inv - value;
1041                value & params.msg_mask()
1042            }
1043       };
1044        |params: &DigitParameters, _deg| params.msg_mask();
1045    },
1046    @1 =>{
1047        |params: &DigitParameters, val | {
1048            let inv = 2;
1049            let mut value =  val & params.data_mask();
1050            if value > inv {
1051                0
1052            } else {
1053                value = inv - value;
1054                value >> params.msg_w
1055            }
1056       };
1057        |_params: &DigitParameters, _deg| 1;
1058    },
1059]],
1060
1061["ManyInv3CarryMsg" => 66 [ // Proceed Inv - ct
1062        // Extract message and carry using many LUT.
1063    @0 =>{
1064        |params: &DigitParameters, val | {
1065            let inv = 3;
1066            let mut value =  val & params.data_mask();
1067            if value > inv {
1068                0
1069            } else {
1070                value = inv - value;
1071                value & params.msg_mask()
1072            }
1073       };
1074        |params: &DigitParameters, _deg| params.msg_mask();
1075    },
1076    @1 =>{
1077        |params: &DigitParameters, val | {
1078            let inv = 3;
1079            let mut value =  val & params.data_mask();
1080            if value > inv {
1081                0
1082            } else {
1083                value = inv - value;
1084                value >> params.msg_w
1085            }
1086       };
1087        |_params: &DigitParameters, _deg| 1;
1088    },
1089]],
1090
1091["ManyInv4CarryMsg" => 67 [ // Proceed Inv - ct
1092        // Extract message and carry using many LUT.
1093    @0 =>{
1094        |params: &DigitParameters, val | {
1095            let inv = 4;
1096            let mut value =  val & params.data_mask();
1097            if value > inv {
1098                0
1099            } else {
1100                value = inv - value;
1101                value & params.msg_mask()
1102            }
1103       };
1104        |params: &DigitParameters, _deg| params.msg_mask();
1105    },
1106    @1 =>{
1107        |params: &DigitParameters, val | {
1108            let inv = 4;
1109            let mut value =  val & params.data_mask();
1110            if value > inv {
1111                0
1112            } else {
1113                value = inv - value;
1114                value >> params.msg_w
1115            }
1116       };
1117        |_params: &DigitParameters, _deg| 1;
1118    },
1119]],
1120
1121["ManyInv5CarryMsg" => 68 [ // Proceed Inv - ct
1122        // Extract message and carry using many LUT.
1123    @0 =>{
1124        |params: &DigitParameters, val | {
1125            let inv = 5;
1126            let mut value =  val & params.data_mask();
1127            if value > inv {
1128                0
1129            } else {
1130                value = inv - value;
1131                value & params.msg_mask()
1132            }
1133       };
1134        |params: &DigitParameters, _deg| params.msg_mask();
1135    },
1136    @1 =>{
1137        |params: &DigitParameters, val | {
1138            let inv = 5;
1139            let mut value =  val & params.data_mask();
1140            if value > inv {
1141                0
1142            } else {
1143                value = inv - value;
1144                value >> params.msg_w
1145            }
1146       };
1147        |_params: &DigitParameters, _deg| 1;
1148    },
1149]],
1150
1151["ManyInv6CarryMsg" => 69 [ // Proceed Inv - ct
1152        // Extract message and carry using many LUT.
1153    @0 =>{
1154        |params: &DigitParameters, val | {
1155            let inv = 6;
1156            let mut value =  val & params.data_mask();
1157            if value > inv {
1158                0
1159            } else {
1160                value = inv - value;
1161                value & params.msg_mask()
1162            }
1163       };
1164        |params: &DigitParameters, _deg| params.msg_mask();
1165    },
1166    @1 =>{
1167        |params: &DigitParameters, val | {
1168            let inv = 6;
1169            let mut value =  val & params.data_mask();
1170            if value > inv {
1171                0
1172            } else {
1173                value = inv - value;
1174                value >> params.msg_w
1175            }
1176       };
1177        |_params: &DigitParameters, _deg| 1;
1178    },
1179]],
1180
1181["ManyInv7CarryMsg" => 70 [ // Proceed Inv - ct
1182        // Extract message and carry using many LUT.
1183    @0 =>{
1184        |params: &DigitParameters, val | {
1185            let inv = 7;
1186            let mut value =  val & params.data_mask();
1187            if value > inv {
1188                0
1189            } else {
1190                value = inv - value;
1191                value & params.msg_mask()
1192            }
1193       };
1194        |params: &DigitParameters, _deg| params.msg_mask();
1195    },
1196    @1 =>{
1197        |params: &DigitParameters, val | {
1198            let inv = 7;
1199            let mut value =  val & params.data_mask();
1200            if value > inv {
1201                0
1202            } else {
1203                value = inv - value;
1204                value >> params.msg_w
1205            }
1206       };
1207        |_params: &DigitParameters, _deg| 1;
1208    },
1209]],
1210["ManyMsgSplit" => 71 [ // Use manyLUT : split msg in halves
1211    @0 =>{
1212        |params: &DigitParameters, val| {
1213                let lsb_size = params.msg_w.div_ceil(2);
1214                val & ((1 << lsb_size)-1) // msg_lsb
1215        };
1216        |params: &DigitParameters, _deg| {
1217                let lsb_size = params.msg_w.div_ceil(2);
1218                (1 << lsb_size)-1
1219        };
1220    },
1221    @1 =>{
1222        |params: &DigitParameters, val| {
1223                let lsb_size = params.msg_w.div_ceil(2);
1224                (val & params.msg_mask()) >> lsb_size // msg_msb
1225        };
1226        |params: &DigitParameters, _deg| {
1227                let lsb_size = params.msg_w.div_ceil(2);
1228                let msb_size = params.msg_w - lsb_size;
1229                (1 << msb_size)-1
1230        };
1231    }
1232]],
1233["Manym2lPropBit1MsgSplit" => 72 [ // Use ManyLut
1234        // In carry part, contains the info if neighbor has a bit=1 (not null)
1235        // or not (null).
1236        // Propagate bits equal to 1 from msb to lsb.
1237        // Split resulting message part into 2. Put both in lsb.
1238    @0 =>{
1239        |params: &DigitParameters, val| {
1240                let mut c = val & params.carry_mask();
1241                let mut m = val & params.msg_mask();
1242                let mut exp = 0;
1243                // Expand from msb to lsb
1244                for idx in (0..params.msg_w).rev() {
1245                    let mut b = (m >> idx) & 1;
1246                    m &= (1 << idx)-1;
1247                    if c > 0 {b = 1;} // propagate to lsb
1248                    if b == 1 {c = 1;}
1249                    exp += b << idx;
1250                }
1251                let lsb_size = params.msg_w.div_ceil(2);
1252                exp & ((1 << lsb_size)-1) // msg_lsb
1253        };
1254        |params: &DigitParameters, _deg| {
1255                let lsb_size = params.msg_w.div_ceil(2);
1256                (1 << lsb_size)-1
1257        };
1258    },
1259    @1 =>{
1260        |params: &DigitParameters, val| {
1261                let mut c = val & params.carry_mask();
1262                let mut m = val & params.msg_mask();
1263                let mut exp = 0;
1264                // Expand from msb to lsb
1265                for idx in (0..params.msg_w).rev() {
1266                    let mut b = (m >> idx) & 1;
1267                    m &= (1 << idx)-1;
1268                    if c > 0 {b = 1;} // propagate to lsb
1269                    if b == 1 {c = 1;}
1270                    exp += b << idx;
1271                }
1272                let lsb_size = params.msg_w.div_ceil(2);
1273                (exp & params.msg_mask()) >> lsb_size // msg_msb
1274        };
1275        |params: &DigitParameters, _deg| {
1276                let lsb_size = params.msg_w.div_ceil(2);
1277                let msb_size = params.msg_w - lsb_size;
1278                (1 << msb_size)-1
1279        };
1280    }
1281]],
1282["Manym2lPropBit0MsgSplit" => 73 [ // Use ManyLut
1283        // In carry part, contains the info if neighbor has a bit=0 (not null)
1284        // or not (null).
1285        // Propagate bits equal to 0 from msb to lsb.
1286        // Split resulting message part into 2. Put both in lsb.
1287    @0 =>{
1288        |params: &DigitParameters, val| {
1289                let mut c = val & params.carry_mask();
1290                let mut m = val & params.msg_mask();
1291                let mut exp = 0;
1292                // Expand from msb to lsb
1293                for idx in (0..(params.msg_w)).rev() {
1294                    let mut b = (m >> idx) & 1;
1295                    m &= (1 << idx)-1;
1296                    if c > 0 {b = 0;} // propagate to lsb
1297                    if b == 0 {c = 1;}
1298                    exp += b << idx;
1299                }
1300                let lsb_size = params.msg_w.div_ceil(2);
1301                exp & ((1 << lsb_size)-1) // msg_lsb
1302        };
1303        |params: &DigitParameters, _deg| {
1304                let lsb_size = params.msg_w.div_ceil(2);
1305                (1 << lsb_size)-1
1306        };
1307    },
1308    @1 =>{
1309        |params: &DigitParameters, val| {
1310                let mut c = val & params.carry_mask();
1311                let mut m = val & params.msg_mask();
1312                let mut exp = 0;
1313                // Expand from msb to lsb
1314                for idx in (0..(params.msg_w)).rev() {
1315                    let mut b = (m >> idx) & 1;
1316                    m &= (1 << idx)-1;
1317                    if c > 0 {b = 0;} // propagate to lsb
1318                    if b == 0 {c = 1;}
1319                    exp += b << idx;
1320                }
1321                let lsb_size = params.msg_w.div_ceil(2);
1322                (exp & params.msg_mask()) >> lsb_size // msg_msb
1323        };
1324        |params: &DigitParameters, _deg| {
1325                let lsb_size = params.msg_w.div_ceil(2);
1326                let msb_size = params.msg_w - lsb_size;
1327                (1 << msb_size)-1
1328        };
1329    }
1330]],
1331["Manyl2mPropBit1MsgSplit" => 74 [ // Use ManyLut
1332        // In carry part, contains the info if neighbor has a bit=1 (not null)
1333        // or not (null).
1334        // Propagate bits equal to 1 from lsb to msb.
1335        // Split resulting message part into 2. Put both in lsb.
1336    @0 =>{
1337        |params: &DigitParameters, val| {
1338                let mut c = val & params.carry_mask();
1339                let mut m = val & params.msg_mask();
1340                let mut exp = 0;
1341                // Expand from lsb to msb
1342                for idx in 0..(params.msg_w) {
1343                    let mut b = m & 1;
1344                    m >>= 1;
1345                    if c > 0 {b = 1;} // propagate to msb
1346                    if b == 1 {c = 1;}
1347                    exp += b << idx;
1348                }
1349                let lsb_size = params.msg_w.div_ceil(2);
1350                exp & ((1 << lsb_size)-1) // msg_lsb
1351        };
1352        |params: &DigitParameters, _deg| {
1353                let lsb_size = params.msg_w.div_ceil(2);
1354                (1 << lsb_size)-1
1355        };
1356    },
1357    @1 =>{
1358        |params: &DigitParameters, val| {
1359                let mut c = val & params.carry_mask();
1360                let mut m = val & params.msg_mask();
1361                let mut exp = 0;
1362                // Expand from lsb to msb
1363                for idx in 0..(params.msg_w) {
1364                    let mut b = m & 1;
1365                    m >>= 1;
1366                    if c > 0 {b = 1;} // propagate to msb
1367                    if b == 1 {c = 1;}
1368                    exp += b << idx;
1369                }
1370                let lsb_size = params.msg_w.div_ceil(2);
1371                (exp & params.msg_mask()) >> lsb_size // msg_msb
1372        };
1373        |params: &DigitParameters, _deg| {
1374                let lsb_size = params.msg_w.div_ceil(2);
1375                let msb_size = params.msg_w - lsb_size;
1376                (1 << msb_size)-1
1377        };
1378    }
1379]],
1380["Manyl2mPropBit0MsgSplit" => 75 [ // Use ManyLut
1381        // In carry part, contains the info if neighbor has a bit=0 (not null)
1382        // or not (null).
1383        // Propagate bits equal to 0 from lsb to msb.
1384        // Split resulting message part into 2. Put both in lsb.
1385    @0 =>{
1386        |params: &DigitParameters, val| {
1387                let mut c = val & params.carry_mask();
1388                let mut m = val & params.msg_mask();
1389                let mut exp = 0;
1390                // Expand from lsb to msb
1391                for idx in 0..(params.msg_w) {
1392                    let mut b = m & 1;
1393                    m >>= 1;
1394                    if c > 0 {b = 0;} // propagate to msb
1395                    if b == 0 {c = 1;}
1396                    exp += b << idx;
1397                }
1398                let lsb_size = params.msg_w.div_ceil(2);
1399                exp & ((1 << lsb_size)-1) // msg_lsb
1400        };
1401        |params: &DigitParameters, _deg| {
1402                let lsb_size = params.msg_w.div_ceil(2);
1403                (1 << lsb_size)-1
1404        };
1405    },
1406    @1 =>{
1407        |params: &DigitParameters, val| {
1408                let mut c = val & params.carry_mask();
1409                let mut m = val & params.msg_mask();
1410                let mut exp = 0;
1411                // Expand from lsb to msb
1412                for idx in 0..(params.msg_w) {
1413                    let mut b = m & 1;
1414                    m >>= 1;
1415                    if c > 0 {b = 0;} // propagate to msb
1416                    if b == 0 {c = 1;}
1417                    exp += b << idx;
1418                }
1419                let lsb_size = params.msg_w.div_ceil(2);
1420                (exp & params.msg_mask()) >> lsb_size // msg_msb
1421        };
1422        |params: &DigitParameters, _deg| {
1423                let lsb_size = params.msg_w.div_ceil(2);
1424                let msb_size = params.msg_w - lsb_size;
1425                (1 << msb_size)-1
1426        };
1427    }
1428]],
1429);
1430
1431pub(crate) fn ceil_ilog2(value: &u8) -> u8 {
1432    (value.ilog2() + u32::from(!value.is_power_of_two())) as u8
1433}