logicaffeine_compile/spatial/decode_engine/
lane.rs1use super::numerics::{exact_sum, fadd, ActRow, ActScale, Scale, Words};
18use super::rtl::weights::{Units, UNIT};
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub struct UnitSums {
23 pub products: i64,
25 pub act: i64,
27}
28
29#[derive(Clone, Debug, PartialEq, Eq)]
32pub struct WordSums {
33 pub units: Vec<UnitSums>,
34 pub excess: bool,
35 pub weight: i64,
36}
37
38#[derive(Clone, Debug, PartialEq, Eq)]
40pub struct LaneBlock {
41 pub c: Vec<i64>,
43 pub n: Vec<i64>,
44 pub q: Vec<i64>,
45 pub offset: i64,
47 pub a: Scale,
48 pub b: Scale,
49 pub act: ActScale,
50 pub words: Vec<WordSums>,
51}
52
53pub fn block_sums(blk: &LaneBlock) -> (i128, i128) {
55 let unit = UNIT as i64;
56 let (mut ia, mut ib) = (0i128, 0i128);
57 for w in &blk.words {
58 let excess = if w.excess { 128 } else { 0 };
59 for (u, s) in w.units.iter().enumerate() {
60 let products = s.products - excess * blk.q[u] - blk.offset * s.act + excess * unit * blk.offset;
61 let act = s.act - excess * unit;
62 ia += (w.weight * blk.c[u]) as i128 * products as i128;
63 ib += (w.weight * blk.n[u]) as i128 * act as i128;
64 }
65 }
66 (ia, ib)
67}
68
69pub fn lane(blk: &LaneBlock, acc: f32) -> f32 {
71 let (ia, ib) = block_sums(blk);
72 let mut terms = [(0i128, 0i32); 2];
73 let mut count = 0;
74 for (s, sum) in [(blk.a, ia), (blk.b, ib)] {
75 if s.sig != 0 && sum != 0 {
76 terms[count] = (s.sig as i128 * blk.act.m as i128 * sum, s.exp + blk.act.e);
77 count += 1;
78 }
79 }
80 fadd(acc, exact_sum(&terms[..count]))
81}
82
83pub fn deliver(units: &Units, scales: (Scale, Scale), offset: u32, act: &ActRow, words: Words, b: usize) -> LaneBlock {
86 let len = units.code.len();
87 let start = b * len;
88 let count = len / UNIT;
89 let unit_sums = |a: &dyn Fn(usize) -> i64| -> Vec<UnitSums> {
90 (0..count)
91 .map(|u| {
92 let range = u * UNIT..(u + 1) * UNIT;
93 UnitSums {
94 products: range.clone().map(|i| units.code[i] as i64 * a(start + i)).sum(),
95 act: range.map(|i| a(start + i)).sum(),
96 }
97 })
98 .collect()
99 };
100 let code = |i: usize| act.codes[i] as i64;
101 let word_sums = match words {
102 Words::One => vec![WordSums { units: unit_sums(&|i| code(i) + 128), excess: true, weight: 1 }],
103 Words::Two => vec![
104 WordSums { units: unit_sums(&|i| code(i).div_euclid(256) + 128), excess: true, weight: 256 },
105 WordSums { units: unit_sums(&|i| code(i).rem_euclid(256)), excess: false, weight: 1 },
106 ],
107 };
108 LaneBlock {
109 c: units.c.iter().map(|&v| v as i64).collect(),
110 n: units.n.iter().map(|&v| v as i64).collect(),
111 q: (0..count).map(|u| units.code[u * UNIT..(u + 1) * UNIT].iter().map(|&q| q as i64).sum()).collect(),
112 offset: offset as i64,
113 a: scales.0,
114 b: scales.1,
115 act: act.scales[b],
116 words: word_sums,
117 }
118}
119
120pub const SUB_BLOCK: usize = 32;
124
125pub fn deliver32(units: &Units, scales: (Scale, Scale), offset: u32, act: &ActRow, words: Words, b: usize, s: usize) -> LaneBlock {
129 let block = deliver(units, scales, offset, act, words, b);
130 let first = s * SUB_BLOCK / UNIT;
131 let count = SUB_BLOCK / UNIT;
132 let start = b * units.code.len() + s * SUB_BLOCK;
133 LaneBlock {
134 c: block.c[first..first + count].to_vec(),
135 n: block.n[first..first + count].to_vec(),
136 q: block.q[first..first + count].to_vec(),
137 offset: block.offset,
138 a: block.a,
139 b: block.b,
140 act: act.scales[start / SUB_BLOCK],
141 words: block.words.into_iter().map(|w| WordSums { units: w.units[first..first + count].to_vec(), ..w }).collect(),
142 }
143}
144
145pub fn group(subs: &[LaneBlock], acc: f32) -> f32 {
149 let mut terms = Vec::with_capacity(2 * subs.len());
150 for blk in subs {
151 let (ia, ib) = block_sums(blk);
152 for (s, sum) in [(blk.a, ia), (blk.b, ib)] {
153 if s.sig != 0 && sum != 0 {
154 terms.push((s.sig as i128 * blk.act.m as i128 * sum, s.exp + blk.act.e));
155 }
156 }
157 }
158 fadd(acc, exact_sum(&terms))
159}