1use rhdl::prelude::*;
27
28#[derive(Clone, Copy, Debug, PartialEq, Digital)]
30pub struct Config<const N: usize> {
31 pub init: bool,
33 pub session: b64,
35 pub client: b32,
37 pub members: [b32; N],
39 pub first_request: b64,
41}
42impl<const N: usize> Default for Config<N> {
43 fn default() -> Self {
44 Self {
45 init: false,
46 session: b64(0),
47 client: b32(0),
48 members: [b32(0); N],
49 first_request: b64(0),
50 }
51 }
52}
53
54#[derive(Clone, Copy, Debug, PartialEq, Digital)]
56pub struct Reply<const P: usize> {
57 pub valid: bool,
59 pub sender: b32,
61 pub session: b64,
63 pub client: b32,
65 pub request: b64,
67 pub len: b32,
69 pub data: [b8; P],
71}
72impl<const P: usize> Default for Reply<P> {
73 fn default() -> Self {
74 empty_reply::<P>()
75 }
76}
77
78#[kernel]
80pub fn empty_reply<const P: usize>() -> Reply<P> {
81 Reply::<P> {
82 valid: false,
83 sender: b32(0),
84 session: b64(0),
85 client: b32(0),
86 request: b64(0),
87 len: b32(0),
88 data: [b8(0); P],
89 }
90}
91
92#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
94pub struct Open {
95 pub valid: bool,
97 pub session: b64,
99 pub client: b32,
101 pub request: b64,
103}
104
105#[derive(Clone, Copy, Debug, PartialEq, Digital)]
107pub struct Vote<const P: usize> {
108 pub present: bool,
110 pub len: b32,
112 pub data: [b8; P],
114}
115#[derive(Clone, Copy, Debug, PartialEq, Digital)]
117pub struct Entry<const N: usize, const P: usize> {
118 pub active: bool,
120 pub request: b64,
122 pub votes: [Vote<P>; N],
124 pub complete: bool,
126 pub len: b32,
128 pub data: [b8; P],
130}
131#[kernel]
133pub fn empty_entry<const N: usize, const P: usize>() -> Entry<N, P> {
134 Entry::<N, P> {
135 active: false,
136 request: b64(0),
137 votes: [Vote::<P> {
138 present: false,
139 len: b32(0),
140 data: [b8(0); P],
141 }; N],
142 complete: false,
143 len: b32(0),
144 data: [b8(0); P],
145 }
146}
147
148#[derive(Clone, Copy, Debug, PartialEq, Digital)]
150pub struct CollectorState<const N: usize, const W: usize, const P: usize> {
151 pub initialized: bool,
153 pub retired: bool,
155 pub cfg: Config<N>,
157 pub entries: [Entry<N, P>; W],
159 pub head: b3,
161 pub tail: b3,
163 pub used: b4,
165 pub next_request: b64,
167 pub exhausted: bool,
169 pub rejected: b32,
171 pub duplicates: b32,
173}
174impl<const N: usize, const W: usize, const P: usize> Default for CollectorState<N, W, P> {
175 fn default() -> Self {
176 Self {
177 initialized: false,
178 retired: false,
179 cfg: Config::default(),
180 entries: [empty_entry::<N, P>(); W],
181 head: b3(0),
182 tail: b3(0),
183 used: b4(0),
184 next_request: b64(0),
185 exhausted: false,
186 rejected: b32(0),
187 duplicates: b32(0),
188 }
189 }
190}
191#[derive(Clone, Copy, Debug, PartialEq, Digital)]
193pub struct CollectorIn<const N: usize, const P: usize> {
194 pub cfg: Config<N>,
196 pub reset: bool,
198 pub open: Open,
200 pub reply: Reply<P>,
202 pub result_ready: bool,
204}
205impl<const N: usize, const P: usize> Default for CollectorIn<N, P> {
206 fn default() -> Self {
207 Self {
208 cfg: Config::default(),
209 reset: false,
210 open: Open::default(),
211 reply: Reply::default(),
212 result_ready: false,
213 }
214 }
215}
216#[derive(Clone, Copy, Debug, PartialEq, Digital)]
218pub struct CollectorOut<const P: usize> {
219 pub open_ready: bool,
221 pub reply_ready: bool,
223 pub result: Reply<P>,
226 pub retired: bool,
228 pub config_rejected: bool,
230}
231
232#[kernel]
234pub fn collect<const N: usize, const W: usize, const P: usize>(
235 i: CollectorIn<N, P>,
236 r: CollectorState<N, W, P>,
237) -> (CollectorOut<P>, CollectorState<N, W, P>) {
238 let mut s = r;
239 let mut o = CollectorOut::<P> {
240 open_ready: false,
241 reply_ready: false,
242 result: empty_reply::<P>(),
243 retired: r.retired,
244 config_rejected: r.initialized && i.cfg.init,
245 };
246 if !r.initialized && !r.retired && i.cfg.init {
247 let mut valid = N >= 1
248 && N <= 15
249 && (N & 1) == 1
250 && W >= 1
251 && W <= 8
252 && P >= 1
253 && P <= 4294967295usize
254 && i.cfg.session != b64(0);
255 for a in 0..N {
256 for b in 0..N {
257 if a != b && i.cfg.members[a] == i.cfg.members[b] {
258 valid = false;
259 }
260 }
261 }
262 if valid {
263 s.initialized = true;
264 s.cfg = i.cfg;
265 s.next_request = i.cfg.first_request;
266 } else {
267 s.retired = true;
268 }
269 }
270 let run = r.initialized && !r.retired && !i.reset;
271 if run {
272 o.open_ready = r.used < b4(W as u128) && !r.exhausted;
273 o.reply_ready = true;
274 for k in 0..W {
275 let e = r.entries[k];
276 if r.head == b3(k as u128) && e.active && e.complete {
277 o.result = Reply::<P> {
278 valid: true,
279 sender: b32(0),
280 session: r.cfg.session,
281 client: r.cfg.client,
282 request: e.request,
283 len: e.len,
284 data: e.data,
285 };
286 }
287 }
288 let retire = o.result.valid && i.result_ready;
289 let allocate = i.open.valid
290 && o.open_ready
291 && i.open.session == r.cfg.session
292 && i.open.client == r.cfg.client
293 && i.open.request == r.next_request;
294 if i.open.valid && o.open_ready && !allocate {
295 s.rejected = s.rejected + b32(1);
296 }
297 if allocate {
298 for k in 0..W {
299 if r.tail == b3(k as u128) {
300 s.entries[k] = empty_entry::<N, P>();
301 s.entries[k].active = true;
302 s.entries[k].request = i.open.request;
303 }
304 }
305 s.tail = if r.tail == b3((W - 1) as u128) {
306 b3(0)
307 } else {
308 r.tail + b3(1)
309 };
310 if r.next_request == !b64(0) {
311 s.exhausted = true;
312 } else {
313 s.next_request = r.next_request + b64(1);
314 }
315 }
316 if retire {
317 for k in 0..W {
318 if r.head == b3(k as u128) {
319 s.entries[k] = empty_entry::<N, P>();
320 }
321 }
322 s.head = if r.head == b3((W - 1) as u128) {
323 b3(0)
324 } else {
325 r.head + b3(1)
326 };
327 }
328 if allocate && !retire {
329 s.used = r.used + b4(1);
330 }
331 if retire && !allocate {
332 s.used = r.used - b4(1);
333 }
334 if i.reply.valid {
335 let mut member = false;
336 for a in 0..N {
337 if r.cfg.members[a] == i.reply.sender {
338 member = true;
339 }
340 }
341 let names = i.reply.session == r.cfg.session
342 && i.reply.client == r.cfg.client
343 && i.reply.len <= b32(P as u128)
344 && member;
345 let mut found = false;
346 let mut bytes = [b8(0); P];
347 for b in 0..P {
348 if b32(b as u128) < i.reply.len {
349 bytes[b] = i.reply.data[b];
350 }
351 }
352 for k in 0..W {
353 let e = r.entries[k];
354 if names
355 && e.active
356 && e.request == i.reply.request
357 && !(retire && r.head == b3(k as u128))
358 {
359 found = true;
360 if !e.complete {
361 for a in 0..N {
362 if r.cfg.members[a] == i.reply.sender {
363 if e.votes[a].present {
364 s.duplicates = s.duplicates + b32(1);
365 } else {
366 s.entries[k].votes[a] = Vote::<P> {
367 present: true,
368 len: i.reply.len,
369 data: bytes,
370 };
371 }
372 }
373 }
374 for a in 0..N {
377 let candidate = s.entries[k].votes[a];
378 let mut count = b5(0);
379 for b in 0..N {
380 let v = s.entries[k].votes[b];
381 if candidate.present
382 && v.present
383 && candidate.len == v.len
384 && candidate.data == v.data
385 {
386 count = count + b5(1);
387 }
388 }
389 if count > b5((N >> 1) as u128) {
390 s.entries[k].complete = true;
391 s.entries[k].len = candidate.len;
392 s.entries[k].data = candidate.data;
393 }
394 }
395 }
396 }
397 }
398 if !found {
399 s.rejected = s.rejected + b32(1);
400 }
401 }
402 }
403 if i.reset {
404 s.retired = true;
405 }
406 (o, s)
407}
408
409#[derive(Clone, Copy, Debug, PartialEq, Digital)]
411pub struct ServerIn<const N: usize, const P: usize> {
412 pub cfg: Config<N>,
414 pub identity: b32,
416 pub executed: Reply<P>,
418 pub reply_ready: bool,
420 pub reset: bool,
422}
423impl<const N: usize, const P: usize> Default for ServerIn<N, P> {
424 fn default() -> Self {
425 Self {
426 cfg: Config::default(),
427 identity: b32(0),
428 executed: Reply::default(),
429 reply_ready: false,
430 reset: false,
431 }
432 }
433}
434#[derive(Clone, Copy, Debug, PartialEq, Digital)]
436pub struct ServerState<const N: usize, const P: usize> {
437 pub initialized: bool,
439 pub retired: bool,
441 pub cfg: Config<N>,
443 pub identity: b32,
445 pub held: Reply<P>,
447 pub rejected: b32,
449}
450impl<const N: usize, const P: usize> Default for ServerState<N, P> {
451 fn default() -> Self {
452 Self {
453 initialized: false,
454 retired: false,
455 cfg: Config::default(),
456 identity: b32(0),
457 held: Reply::default(),
458 rejected: b32(0),
459 }
460 }
461}
462#[derive(Clone, Copy, Debug, PartialEq, Digital)]
464pub struct ServerOut<const P: usize> {
465 pub execution_ready: bool,
467 pub reply: Reply<P>,
469 pub retired: bool,
471 pub config_rejected: bool,
473}
474#[kernel]
476pub fn serve<const N: usize, const P: usize>(
477 i: ServerIn<N, P>,
478 r: ServerState<N, P>,
479) -> (ServerOut<P>, ServerState<N, P>) {
480 let mut s = r;
481 let mut o = ServerOut::<P> {
482 execution_ready: false,
483 reply: empty_reply::<P>(),
484 retired: r.retired,
485 config_rejected: r.initialized && i.cfg.init,
486 };
487 if !r.initialized && !r.retired && i.cfg.init {
488 let mut own = false;
489 let mut valid = N >= 1
490 && N <= 15
491 && (N & 1) == 1
492 && P >= 1
493 && P <= 4294967295usize
494 && i.cfg.session != b64(0);
495 for a in 0..N {
496 if i.cfg.members[a] == i.identity {
497 own = true;
498 }
499 for b in 0..N {
500 if a != b && i.cfg.members[a] == i.cfg.members[b] {
501 valid = false;
502 }
503 }
504 }
505 if valid && own {
506 s.initialized = true;
507 s.cfg = i.cfg;
508 s.identity = i.identity;
509 } else {
510 s.retired = true;
511 }
512 }
513 if r.initialized && !r.retired && !i.reset {
514 o.reply = r.held;
515 o.execution_ready = !r.held.valid;
516 if r.held.valid && i.reply_ready {
517 s.held = empty_reply::<P>();
518 }
519 if i.executed.valid && o.execution_ready {
520 if i.executed.session == r.cfg.session
521 && i.executed.client == r.cfg.client
522 && i.executed.len <= b32(P as u128)
523 {
524 s.held = i.executed;
525 s.held.sender = r.identity;
526 for b in 0..P {
527 if b32(b as u128) >= i.executed.len {
528 s.held.data[b] = b8(0);
529 }
530 }
531 } else {
532 s.rejected = r.rejected + b32(1);
533 }
534 }
535 }
536 if i.reset {
537 s.retired = true;
538 }
539 (o, s)
540}