forked from ceu-lang/ceu-sdl
-
Notifications
You must be signed in to change notification settings - Fork 1
/
timemachine.ceu
1035 lines (935 loc) · 30.9 KB
/
timemachine.ceu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
input bool OS_RESUME, OS_PAUSE;
native do
enum {
TM_REQ_PAUSE = -1,
};
end
native @nohold _snap_seek();
#ifndef TM_INPUT_DT
#error "Missing TM_INPUT_DT"
#endif
#ifdef TM_QUEUE
#if 0
_printf("TM_QUEUE:\n");
_printf("\tQUEUE_N %d\n", TM_QUEUE_N);
_printf("\tT_QUEUE_DT %ld\n", sizeof(_tceu_queue_dt));
_printf("\tT_QUEUE %ld\n", sizeof(_tceu_queue));
#endif
# ifdef TM_QUEUE_WCLOCK_REUSE
#if 0
_printf("\tWCLOCK_REUSE\n");
#endif
# endif
# ifndef TM_QUEUE_N
# error "Missing TM_QUEUE_N"
# endif
#else
# ifdef TM_QUEUE_WCLOCK_REUSE
# error "TM_QUEUE_WCLOCK_REUSE requires TM_QUEUE"
# endif
#endif
#ifdef TM_SNAP
# ifndef TM_SNAP_N
# error "Missing TM_SNAP_N"
# endif
#if 0
_printf("TM_SNAP:\n");
_printf("\tSNAP_N %d\n", TM_SNAP_N);
#endif
# if defined(TM_QUEUE) || defined(TM_DIFF)
# define TM_SNAP_QUEUE_DIFF
# ifndef TM_SNAP_MS
# error "Missing TM_SNAP_MS"
# endif
# else
# ifdef TM_SNAP_MS
# error "!(TM_QUEUE||TM_DIFF) and TM_SNAP_MS are incompatible"
# endif
# endif
#endif
#ifdef TM_DIFF
#if 0
_printf("TM_DIFF:\n");
_printf("\tDIFF_N %d\n", TM_DIFF_N);
#endif
# ifndef TM_DIFF_N
# error "Missing TM_DIFF_N"
# endif
#endif
#if defined(TM_QUEUE) && defined(TM_DIFF)
# error "TM_QUEUE and TM_DIFF are incompatible"
#endif
#ifdef TM_QUEUE
interface IIOTimeMachine with
event void go_on;
event void go_off;
event _tceu_queue* go_queue;
end
#endif
#ifdef TM_FPS
class Fps with
event int go;
do
var int fps = 0; /* previous FPS */
loop do
var int c = 0; /* reset the current counter */
var int t;
watching 10s_ do
every t in this.go do
c = c + 1;
end
end
fps = c;
/*
#if 0
_printf("[FPS=%d (%ds)]\n", fps, t/10);
_printf("%d %d\n", t/10, fps);
*/
end
end
#endif
class TimeMachine with
var App& app;
#ifdef TM_QUEUE
var IIOTimeMachine& io;
#endif
event void go_on, go_off;
//event void ok_restart;
event int go_seek;
event void go_pause;
event int go_backward;
event int go_forward;
var bool locked = false;
var bool ticking = false;
event void ok_tick;
var bool seeking = false;
event int ok_seek;
#define TM_AWAIT_SEEK(me) \
if me.ticking then \
await me.ok_tick; \
end \
if me.seeking then \
await me.ok_seek; \
end
var int time_total = 0;
var int time_now;
do
#ifdef TM_SNAP
_snap_init((u8*)&this.app)
finalize with
nothing; // app is supposed to live longer than TM
end;
#ifdef TM_SNAP_QUEUE_DIFF
var int next_snap = TM_SNAP_MS;
#endif
#else // !TM_SNAP
native do
CEU_App CEU_APP_0; /* saves application state-0 */
end
_CEU_APP_0 = *((CEU_App*)&this.app);
#ifdef TM_QUEUE
_queue_seek(0);
#endif
#endif // TM_SNAP
#ifdef TM_DIFF
_diff_init((u8*)&this.app)
finalize with
nothing; // app is supposed to live longer than TM
end;
#endif
loop do
watching this.go_on do
var int dt;
every dt in TM_INPUT_DT do
/*
var int c = 0;
loop do
dt = await TM_INPUT_DT;
*/
this.time_total = this.time_total + dt;
_assert(dt >= 0);
#ifdef TM_DIFF
_diff_put(this.time_total);
#endif
#if defined TM_SNAP_QUEUE_DIFF
var u32 brk_time = 0;
if this.time_total >= next_snap then
brk_time = this.time_total;
next_snap = next_snap + TM_SNAP_MS;
end
if brk_time > 0 then
_snap_put(brk_time);
end
#elif defined TM_SNAP
_snap_put(this.time_total);
#endif
#ifdef TM_QUEUE
#ifdef TM_SNAP
_queue_put(_CEU_IN__WCLOCK, 0, &dt, brk_time)
#else
_queue_put(_CEU_IN__WCLOCK, 0, &dt)
#endif
#endif
finalize with
nothing;
end;
end
end
_assert(_CEU_TIMEMACHINE_ON == 0);
_CEU_TIMEMACHINE_ON = 1;
async do
emit OS_PAUSE => true;
end
#ifdef TM_QUEUE
emit this.io.go_on;
#endif
par/or do
finalize with
_CEU_TIMEMACHINE_ON = 0;
this.time_total = time_now; // drop future
#if defined TM_QUEUE
_queue_drop();
#elif defined TM_DIFF
_diff_drop();
#endif
#ifdef TM_SNAP
#ifdef TM_SNAP_QUEUE_DIFF
next_snap = _snap_drop(time_now);
#else
_snap_drop(time_now);
#endif
#endif
end
await this.go_off;
TM_AWAIT_SEEK(this);
async do
emit OS_RESUME => true;
end
#ifdef TM_QUEUE
emit this.io.go_off;
#endif
with
var int speed = 0;
// initialization avoids valgrind "uninitalized access" below
event int e_backward;
var int time_req = _TM_REQ_PAUSE;
time_now = this.time_total; // start in the end (the current state)
#if defined TM_QUEUE
_queue_toend();
#elif defined TM_DIFF
_diff_toend();
#else
_snap_toend();
#endif
#ifdef TM_FPS
var Fps fps;
#endif
par do
loop do
par/or do
var int tmp = await this.go_seek;
// avoid conflict w/ ongoing time_req
TM_AWAIT_SEEK(this);
time_req = tmp;
_assert(time_req <= this.time_total);
#ifdef TM_SNAP
#if defined TM_QUEUE
var u32 queue;
this.time_now = _snap_seek(time_req, &queue);
_queue_seek(queue);
#elif defined TM_DIFF
var u32 diffs;
this.time_now = _snap_seek(time_req, &diffs);
_DIFF.nxt = diffs;
_memcpy(_DIFF.data_old, _DIFF.data, sizeof(_CEU_App));
this.time_now = _diff_seek(time_req);
#else
this.time_now = _snap_seek(time_req);
#endif
#else // !TM_SNAP
#if defined TM_QUEUE
*((_CEU_App*)&app) = _CEU_APP_0;
_queue_seek(0);
this.time_now = 0;
#elif defined TM_DIFF
this.time_now = _diff_seek(time_req);
#endif
#endif // TM_SNAP
speed = 0;
this.seeking = true;
//emit this.ok_restart;
with
await this.go_pause;
TM_AWAIT_SEEK(this);
time_req = _TM_REQ_PAUSE;
with
var int s = await this.go_backward;
TM_AWAIT_SEEK(this);
speed = s;
emit e_backward => s;
await FOREVER; // e_backward emits go_seek
with
var int s = await this.go_forward;
TM_AWAIT_SEEK(this);
speed = s;
time_req = this.time_total;
with
#ifndef TM_DELAY
var int late = 0;
#endif
loop do
if time_req == _TM_REQ_PAUSE then
break; // already there
end
var int dt = 0;
#if defined TM_QUEUE
var _tceu_queue&? qu;
finalize
qu = _queue_nxt(time_now, time_req);
with
nothing;
end
if not qu? then
break;
end
this.ticking = true;
if qu.evt == _CEU_IN__WCLOCK then
#ifdef TM_QUEUE_WCLOCK_REUSE
dt = (1000/_CEU_FPS);
#else
dt = ((_tceu_queue_dt*)&qu):dt;
#endif
_assert(dt >= 0);
time_now = time_now + dt;
this.locked = true;
async(dt) do
emit (dt)ms;
emit TM_INPUT_DT => dt;
end
this.locked = false;
else
emit io.go_queue => &qu;
end
#elif defined TM_DIFF
var u32 time = _diff_nxt(time_now, time_req);
if time == 0 then
break;
end
dt = time - time_now;
time_now = time;
#else // TM_SNAP
var u32 time = _snap_nxt(time_now, time_req);
if time == 0 then
break;
end
dt = time - time_now;
time_now = time;
#endif // TM_QUEUE/TM_SNAP/TM_DIFF
if speed != 0 then
if dt > 0 then
var int awt;
if speed > 0 then
awt = dt/speed;
else // < 0
awt = dt*-speed;
end
#ifdef TM_DELAY
#error Are you sure?
TM_DELAY(awt);
#else
if awt > late then
late = await (awt-late) ms_;
_assert(late%1000 == 0);
late = late / 1000;
else
late = late - awt;
end
#endif
end
#ifdef TM_INPUT_REDRAW
this.locked = true;
#ifdef TM_FPS
emit fps.go => time_now;
#endif
async do
emit OS_RESUME => false;
emit TM_INPUT_REDRAW;
emit OS_PAUSE => false;
end
this.locked = false;
#endif
end
this.ticking = false;
emit this.ok_tick;
end
this.locked = true;
// this async is forced to ensure at least one sync
// break (even if there's no REDRAW event)
#ifdef TM_FPS
emit fps.go => time_now;
#endif
async do
emit OS_RESUME => false;
#ifdef TM_INPUT_REDRAW
emit TM_INPUT_REDRAW;
#endif
emit OS_PAUSE => false;
end
this.locked = false;
if this.seeking then
this.seeking = false;
emit this.ok_seek => time_now;
end
await FOREVER;
end
end
with
var bool go = false;
var int bk_speed;
loop do
var bool me = false;
par/or do
// start on this
bk_speed = await e_backward;
go = true;
with
// stop on any of these
par/or do
await go_seek until (not me);
with
await go_pause;
with
await go_forward;
end
go = false;
with
if not go then
await FOREVER;
end
var int now = this.time_now;
#ifndef TM_BACKWARD_TICK
#define TM_BACKWARD_TICK 30 // TODO: adaptative
#endif
var int awt;
if bk_speed > 0 then
awt = TM_BACKWARD_TICK/bk_speed;
else/if bk_speed < 0 then
awt = TM_BACKWARD_TICK*-bk_speed;
else
_assert(0);
end
var int late = await (awt)ms_; // first iteration
loop i do
now = now - TM_BACKWARD_TICK;
if now < 0 then
now = 0; // one last time to stop exactly at 0
end
me = true;
emit this.go_seek => now; // don't awake myself (above)
me = false;
par/and do
await this.ok_seek;
async do end; // TODO: forced
with
late = late/1000;
var int tot = (awt-late);
if tot > 0 then
late = await (awt-late)ms_; // other iterations
else
late = (late-awt)*1000;
end
end
if now == 0 then
break;
end
end
await FOREVER;
end
end
end
end
end
#ifdef TM_QUEUE
native @plain _tceu_queue;
native/pre do
typedef struct {
tceu_nevt evt;
#ifdef TM_QUEUE_WCLOCK_REUSE
u8 n;
#else
u8 dt;
#endif
} tceu_queue_dt;
typedef struct {
tceu_nevt evt;
s32 sz;
byte buf[0];
} tceu_queue;
typedef struct {
byte buf[TM_QUEUE_N];
u32 tot;
u32 nxt;
u32 put;
u32 put_old;
#ifdef TM_QUEUE_WCLOCK_REUSE
u8 nxt_n;
#endif
} tceu_queue_state;
end
native do
tceu_queue_state QUEUE = {
{}
, 0 /*u32 QUEUE_tot = 0;*/
, 0xaa /*u32 QUEUE_nxt = undef;*/
, 0 /*u32 QUEUE_put = 0;*/
#ifdef TM_QUEUE_WCLOCK_REUSE
, 0 /*u32 QUEUE_put_old = 0;*/
, 0 /*u8 QUEUE_nxt_n = 0;*/
#endif
};
int queue_put (tceu_nevt evt, int sz, void* buf
#ifdef TM_SNAP
, u32 brk_time
#endif
)
{
int n = (evt==CEU_IN__WCLOCK) ? sizeof(tceu_queue_dt) :
sizeof(tceu_queue) + sz;
assert(QUEUE.tot+n <= TM_QUEUE_N);
if (evt == CEU_IN__WCLOCK) {
#ifdef TM_QUEUE_WCLOCK_REUSE
assert(*((s32*)buf) == (1000/CEU_FPS));
tceu_queue_dt* qo = (tceu_queue_dt*) &QUEUE.buf[QUEUE.put_old];
if (qo->evt==CEU_IN__WCLOCK && QUEUE.put!=QUEUE.put_old && qo->n<255
#ifdef TM_SNAP
&& brk_time>0
#endif
)
{
/* QUEUE.put==QUEUE.put_old means "break now" (either * before init or after drop */
QUEUE.put = QUEUE.put_old;
qo->n++;
QUEUE.tot -= n; /* cancel "+=" below */
} else {
tceu_queue_dt* qn = (tceu_queue_dt*) &QUEUE.buf[QUEUE.put];
qn->evt = CEU_IN__WCLOCK;
qn->n = 1;
}
#else
tceu_queue_dt* qn = (tceu_queue_dt*) &QUEUE.buf[QUEUE.put];
qn->evt = evt;
qn->dt = *((s32*)buf);
#endif
} else {
tceu_queue* qn = (tceu_queue*) &QUEUE.buf[QUEUE.put];
qn->evt = evt;
qn->sz = sz;
memcpy(qn->buf, buf, sz);
}
#ifdef TM_QUEUE_WCLOCK_REUSE
QUEUE.put_old = QUEUE.put;
#endif
QUEUE.put += n;
QUEUE.tot += n;
return 1;
}
tceu_queue* queue_nxt (u32 now, u32 upto) {
if (QUEUE.nxt == QUEUE.put) {
return NULL;
} else {
assert(QUEUE.tot > 0);
tceu_queue* qu = (tceu_queue*) &QUEUE.buf[QUEUE.nxt];
if (qu->evt == CEU_IN__WCLOCK) {
tceu_queue_dt* qu = (tceu_queue_dt*) &QUEUE.buf[QUEUE.nxt];
#ifdef TM_QUEUE_WCLOCK_REUSE
if (now+(1000/CEU_FPS) > upto) {
return NULL; /* do not advance */
}
QUEUE.nxt_n++;
if (QUEUE.nxt_n == qu->n) { /* reached last DT */
QUEUE.nxt_n = 0;
QUEUE.nxt += sizeof(tceu_queue_dt);
}
#else
if (now+qu->dt > upto) {
return NULL; /* do not advance */
}
QUEUE.nxt += sizeof(tceu_queue_dt);
#endif
} else {
#ifdef TM_QUEUE_WCLOCK_REUSE
QUEUE.nxt_n = 0;
#endif
QUEUE.nxt += sizeof(tceu_queue) + qu->sz;
}
return qu;
}
}
void queue_drop (void) {
#ifdef TM_QUEUE_WCLOCK_REUSE
tceu_queue_dt* qu = (tceu_queue_dt*) &QUEUE.buf[QUEUE.nxt];
if (qu->evt == CEU_IN__WCLOCK) {
if (QUEUE.nxt_n == 0) {
/* drop current slot */
} else {
qu->n = QUEUE.nxt_n; /* replace with new max */
QUEUE.nxt += sizeof(tceu_queue_dt); /* keep current slot */
}
}
QUEUE.nxt_n = 0;
#endif
QUEUE.put
#ifdef TM_QUEUE_WCLOCK_REUSE
= QUEUE.put_old
#endif
= QUEUE.tot
= QUEUE.nxt;
}
void queue_toend (void) {
QUEUE.nxt = QUEUE.put;
#ifdef TM_QUEUE_WCLOCK_REUSE
QUEUE.put_old = QUEUE.put;
QUEUE.nxt_n = 0;
#endif
}
void queue_seek (u32 nxt) {
QUEUE.nxt = nxt;
#ifdef TM_QUEUE_WCLOCK_REUSE
QUEUE.nxt_n = 0;
#endif
}
#if 0
void queue_dump (void) {
u32 i;
int DT = 0;
printf("DUMP: %d\n", QUEUE.tot);
for (i=0; i<=QUEUE.tot;) {
tceu_queue* qu = (tceu_queue*) &QUEUE.buf[i];
if (qu->evt == CEU_IN__WCLOCK) {
#ifdef TM_QUEUE_WCLOCK_REUSE
printf("[%3d:%ddt] ", i, ((tceu_queue_dt*)qu)->n);
#else
printf("[%3d:%dms] ", i, ((tceu_queue_dt*)qu)->dt);
#endif
DT += 1;/*((tceu_queue_dt*)qu)->dt;*/
i += sizeof(tceu_queue_dt);
} else {
printf("[%d:%de] ", i, qu->evt);
i += sizeof(tceu_queue) + qu->sz;
}
}
printf("\n==>%d\n", DT);
}
#endif
end
#endif // TM_QUEUE
/* ***************************************************************** */
#ifdef TM_DIFF
native do
typedef struct {
u32 offset;
u8 from;
u8 to; /* TODO: u8=>u16/u32? */
} tceu_diff;
typedef struct {
u16 prv;
u16 n;
u32 time;
tceu_diff vec[0];
} tceu_diffs;
typedef struct {
u32 put;
u8* data;
u8 data_old[sizeof(CEU_App)];
u32 nxt;
u8 buf[TM_DIFF_N];
} tceu_diff_state;
#define TM_DIFF_BUF(i) (*((tceu_diffs*)&(DIFF.buf[i])))
#define TM_BUF_SZ(n) (sizeof(tceu_diffs) + (n)*sizeof(tceu_diff))
tceu_diff_state DIFF;
#if 0
void diff_sum (u32 cur) {
u32 sum1 = 0;
{
int n = 0;
for (n=0; n<TM_DIFF_BUF(cur).n; n++) {
u32 off = TM_DIFF_BUF(cur).vec[n].offset;
u8 fr = TM_DIFF_BUF(cur).vec[n].from;
u8 to = TM_DIFF_BUF(cur).vec[n].to;
sum1 += to;
}
}
u32 sum2 = 0;
{
u32 n = 0;
for (n=0; n<sizeof(CEU_App); n++) {
sum2 += DIFF.data_old[n];
}
}
printf("CUR[%d] = %d/%d (%dms)\n", cur, sum1, sum2, TM_DIFF_BUF(cur).time);
}
void diff_dump (void) {
u32 i = 0;
printf(">>> DUMP\n");
while (i < DIFF.put) {
int n;
printf("====== %d (%dms)\n", i, TM_DIFF_BUF(i).time);
diff_sum(i);
for (n=0; n<TM_DIFF_BUF(i).n; n++) {
u32 off = TM_DIFF_BUF(i).vec[n].offset;
u8 fr = TM_DIFF_BUF(i).vec[n].from;
u8 to = TM_DIFF_BUF(i).vec[n].to;
printf("|[%d]%d:%d", off,fr,to);
}
printf("\n");
i += TM_BUF_SZ(TM_DIFF_BUF(i).n);
}
printf("<<< DUMP\n");
}
#endif
void diff_put (u32 time) {
/* fill "put" */
u32 i;
u32 n = 0;
for (i=0; i<sizeof(CEU_App); i++) {
u8 fr = DIFF.data_old[i];
u8 to = DIFF.data[i];
if (fr != to) {
assert(DIFF.put+TM_BUF_SZ(n) < TM_DIFF_N);
TM_DIFF_BUF(DIFF.put).vec[n].offset = i;
TM_DIFF_BUF(DIFF.put).vec[n].from = fr;
TM_DIFF_BUF(DIFF.put).vec[n].to = to;
n++;
assert(n < 65536);
}
}
TM_DIFF_BUF(DIFF.put).time = time;
TM_DIFF_BUF(DIFF.put).n = n;
/* replace with new current */
memcpy(DIFF.data_old, DIFF.data, sizeof(CEU_App));
/* update "put" */
DIFF.put += TM_BUF_SZ(n);
/* "data_old" holds the data previous to "nxt" */
DIFF.nxt = DIFF.put;
/* set backlink for the next put */
assert(DIFF.put+TM_BUF_SZ(0) < TM_DIFF_N);
TM_DIFF_BUF(DIFF.put).prv = TM_BUF_SZ(n);
{
u32 cur = DIFF.nxt - TM_DIFF_BUF(DIFF.nxt).prv;
int n = 0;
for (n=0; n<TM_DIFF_BUF(cur).n; n++) {
u32 off = TM_DIFF_BUF(cur).vec[n].offset;
u8 fr = TM_DIFF_BUF(cur).vec[n].from;
u8 to = TM_DIFF_BUF(cur).vec[n].to;
assert(DIFF.data_old[off] == to);
}
/*diff_sum(cur);*/
}
}
void diff_drop (void) {
DIFF.put = DIFF.nxt;
}
u32 diff_seek (u32 time) {
#ifndef TM_SNAP
/* time=0 is outside DIFF.buf */
if (time == 0) {
DIFF.nxt = 0;
memcpy(DIFF.data, &CEU_APP_0, sizeof(CEU_App));
memcpy(DIFF.data_old, &CEU_APP_0, sizeof(CEU_App));
/*diff_sum(0);*/
return 0;
}
#endif
/* "data_old" holds the data previous to "nxt" */
u32 cur = DIFF.nxt - TM_DIFF_BUF(DIFF.nxt).prv;
/* TODO: droping non-dt events between two dts? */
/* (using data_old below) */
u32 now = ((DIFF.nxt==0) ? 0 : TM_DIFF_BUF(cur).time);
if (now < time) { /* lower --> higher */
cur = DIFF.nxt;
while (1) {
assert(cur+TM_BUF_SZ(TM_DIFF_BUF(cur).n) < TM_DIFF_N);
if (TM_DIFF_BUF(cur).time > time) {
break; /* do not go over "time" */
}
{
int n = 0;
for (n=0; n<TM_DIFF_BUF(cur).n; n++) {
u32 off = TM_DIFF_BUF(cur).vec[n].offset;
u8 fr = TM_DIFF_BUF(cur).vec[n].from;
u8 to = TM_DIFF_BUF(cur).vec[n].to;
assert(DIFF.data_old[off] == fr);
DIFF.data_old[off] = to;
}
}
/*diff_sum(cur);*/
cur += TM_BUF_SZ(TM_DIFF_BUF(cur).n);
DIFF.nxt = cur;
assert(DIFF.nxt < DIFF.put); /* requested time in the future */
if (TM_DIFF_BUF(cur).time == time) {
break;
}
}
} else if (now > time) { /* lower <--- higher */
while (1) {
if (DIFF.nxt == 0) {
break; /* requested time is >0 for sure */
}
u32 prv = cur - TM_DIFF_BUF(cur).prv;
if (TM_DIFF_BUF(prv).time < time) {
break; /* do not go under "time" */
}
/*diff_sum(cur);*/
{
int n = 0;
for (n=0; n<TM_DIFF_BUF(cur).n; n++) {
u32 off = TM_DIFF_BUF(cur).vec[n].offset;
u8 fr = TM_DIFF_BUF(cur).vec[n].from;
u8 to = TM_DIFF_BUF(cur).vec[n].to;
assert(DIFF.data_old[off] == to);
DIFF.data_old[off] = fr;
}
}
DIFF.nxt = cur;
if (cur > 0) {
assert(TM_DIFF_BUF(cur).prv > 0);
assert(cur >= TM_DIFF_BUF(cur).prv);
cur = prv;
}
if (TM_DIFF_BUF(cur).time == time) {
break;
}
assert(TM_DIFF_BUF(cur).time > time);
}
}
memcpy(DIFF.data, DIFF.data_old, sizeof(CEU_App));
return time;
}
u32 diff_nxt (u32 now, u32 upto) {
if (DIFF.nxt == DIFF.put) {
return 0;
} else {
tceu_diffs* s = &TM_DIFF_BUF(DIFF.nxt);
if (s->time > upto) {
return 0; /* do not advance */
}
int n = 0;
for (n=0; n<TM_DIFF_BUF(DIFF.nxt).n; n++) {
u32 off = TM_DIFF_BUF(DIFF.nxt).vec[n].offset;
u8 to = TM_DIFF_BUF(DIFF.nxt).vec[n].to;
DIFF.data[off] = to;
DIFF.data_old[off] = to;
}
/*diff_sum(DIFF.nxt);*/
DIFF.nxt += TM_BUF_SZ(n);
return s->time;
}
}
void diff_toend (void) {
DIFF.nxt = DIFF.put;
}
void diff_init (u8* data) {
DIFF.data = data;
DIFF.put = 0;
DIFF.nxt = 0;
memcpy(DIFF.data_old, DIFF.data, sizeof(CEU_App));
}
end
#endif // TM_DIFF
/* ***************************************************************** */
#ifdef TM_SNAP
native do
typedef struct {
u32 time;
#if defined TM_QUEUE
u32 queue;
#elif defined TM_DIFF
u32 diffs;
#endif
CEU_App data;
} tceu_snap;
typedef struct {
u32 put;
u8* data;
tceu_snap buf[TM_SNAP_N];
#ifndef TM_QUEUE
u32 nxt;
#endif
} tceu_snap_state;
tceu_snap_state SNAP;
void snap_put (u32 time) {
assert(SNAP.put < TM_SNAP_N);
SNAP.buf[SNAP.put].time = time;
SNAP.buf[SNAP.put].data = *((CEU_App*)SNAP.data);
#if defined TM_QUEUE
SNAP.buf[SNAP.put].queue = QUEUE.put_old;
#elif defined TM_DIFF
SNAP.buf[SNAP.put].diffs = DIFF.nxt;
#endif
SNAP.put++;
}
u32 snap_drop (u32 time) {
u32 i;
for (i=0; i<SNAP.put; i++) {
if (SNAP.buf[i].time > time) {
SNAP.put = i;
return SNAP.buf[i].time;
}
}
#ifdef TM_QUEUE
return SNAP.buf[SNAP.put-1].time + TM_SNAP_MS;
#else
return 0; /* return value is ignored anyways */
#endif
}
#if defined TM_QUEUE
u32 snap_seek (u32 time, u32* queue) {
#elif defined TM_DIFF
u32 snap_seek (u32 time, u32* diffs) {
#else
u32 snap_seek (u32 time) {
#endif
u32 i = SNAP.put;
while (1) {
assert(i > 0); /* first put happens on init */
/* i==0 must be found below */
i--;
if (SNAP.buf[i].time <= time) {
*((CEU_App*)SNAP.data) = SNAP.buf[i].data;
#if defined TM_QUEUE
*queue = SNAP.buf[i].queue;
#elif defined TM_DIFF
*diffs = SNAP.buf[i].diffs;
#else /* !TM_SNAP_QUEUE_DIFF */
SNAP.nxt = i+1;