infmachine 0.1.1

The Infinite Machine.
Documentation
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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
#![cfg_attr(docsrs, feature(doc_cfg))]
//! ## InfMachine
//!
//! This is library provide the execution environment for the Infinite machine.
//! Execution environment allow to run machines at CPU and GPU using an OpenCL devices.
//! A machine executed in parallel way and massive processors of that machines are executed
//! parallel way. It possible to run machines with multiple millions processors simultaneously
//! thanks limited states and memories of that processors.
//!
//! The library uses `gatesim` library to operate on machine's circuits.
//! The library uses `gatenative` library to run machine and simulate circuit execution of
//! that machines.
//!
//! ### InfMachine model
//!
//! The Infinite Machine is simple model of infinite machine that has infinite memory and
//! infinite number of processors. Machine described by circuit that has inputs and outputs.
//!
//! The machine contains main memory. Main memory shared by every processor and
//! it can be read and written by any processor.
//! Main memory address starts from 0 and no end of this memory.
//! Main Memory cell length is power of two.
//!
//! Next type of memory is `mem_address` - memory address. Any processor has own private
//! memory address and no other processor can access to this memory address.
//! Memory address is sequential memory with start and no end. Position of memory address
//! points to current part of memory address. Length of part of memory address
//! specified by data part length and it can be any non-zero number. Processor can
//! move position of memory address forward and backward. Memory address points
//! main memory cell of that address that will accessed by processor.
//!
//! Additional type of memory is `temp_buffer` - temporary buffer. Temporary buffer
//! is only name of that memory and it means usage of that memory.
//! Any processor has own private temp buffer and no other processor can access
//! to this temp buffer.
//! Same memory is not temporary. Likewise memory address, temp buffer is sequential memory
//! divided by data parts of length specified by data part length and given position
//! can be moved forward and backward as in memory address.
//!
//! Processor id is private read only memory that contains processor id (private number
//! of processor). It is sequential memory likewise memory address of temp buffer.
//!
//! Internal data is memory address and temp buffer.
//!
//! Any read or write from/to memory address or temp buffer can be done to its part
//! of length `data part length` at current position.
//! Read from memory address or temp buffer done before write to same part of that memory.
//! Position going to be changed after any access to part of internal data.
//!
//! Three parameters defines machine:
//! * state length - length of internal state in bits.
//! * data part length - length of data part of sequential (internal data) memory in bits.
//! For temp_buffer, memory address and processor id.
//! * cell_len_bits - power of two of length of cell of main memory.
//! cell_len_bits=3, then cell is byte (8 bits).
//!
//! Execution of machine divided by cycles. Cycle stage in library starts from 0.
//! Cycles divided by four stages:
//! 1. Circuit execution and handling internal data.
//!     1. Fetch read memory cells to circuit input.
//!     2. Fetch internal data.
//!     3. Execute circuit.
//!     4. Process read/write of internal data.
//!     5. Process position of internal data.
//! 2. Read memory.
//! 3. Clear memory to write.
//! 4. Write memory and stop machine if needed.
//!
//! Initial state of machine is all memories and positions are zeroed.
//!
//! Read from main memory will be done parallel way in stage 2. Write to main memory done
//! in stages 3 and 4. Any cell of main memory going to be cleared before write in stage 3.
//! In stage 4 aggregated write to cell of main memory done by making logical OR operation on
//! bits of cell with all writes from all processors. If any processor writes 1 to some bit
//! same cell of main memory then will be 1 in this bit, otherwise bit will be 0.
//!
//! For model that includes infinite processors we distinguish unique processing:
//! processor that doing different processing by writing different values to memories
//! and having different states. Number of unique processing for any cycle are finite.
//! Main memory writing is computable because: for bit that not set to 1 no processor
//! that store this bit and no duplicate of processor that do it, for bit that set to 1
//! any duplicate of processing make same operation. For bit that set 1 it requires to
//! only one processor to set that bit, other processor doesn't change result.
//!
//! Details of circuits. The circuit of machine describes behavior of machine.
//! Input of circuit is:
//!
//! [STATE, MEMCELL, DATAPART, DATAPART_MOVE_DONE].
//!
//! Output of circuit is:
//!
//! [STATE, MEMCELL, DATAPART, MEMRW, DATAPART_RW, DATAPART_MOVE_DIR, DATA_KIND, STOP_MACHINE].
//!
//! Descriptin of fields:
//! * STATE - internal state of processor (circuit). Any length.
//! * MEMCELL - memory cell value to load or store.
//! * DATAPART - part of internal data loaded or stored from current position of that
//! internal data (temp_buffer of mem_address).
//! * DATAPART_MOVE_DONE - 1-bit. if 1 then position of part changed.
//! * DATAPART_RW - 2-bit control of internal data access:
//!     * 0b00 - nothing,
//!     * 0b01 - read,
//!     * 0b10 - write,
//!     * 0b11 - read and write.
//! * DATAPART_MOVE_DIR - 2-bit direction of position movement:
//!     * 0b00 - nothing,
//!     * 0b01 - move forward,
//!     * 0b10 - move backward,
//!     * 0b11 - move backward.
//! * DATA_KIND - 2-bit kind of internal data:
//!     * 0b00 - memory address,
//!     * 0b01 - temporary buffer,
//!     * 0b10 - id of processor,
//!     * 0b11 - id of processor.
//! * STOP_MACHINE - 1-bit. If value is 1 in any processor then machine going to be stopped.
//!
//! ### Illegal states
//!
//! Illegal state means in only executor environment, but not in machine model.
//! Illegal state happens if any processor try write memory above specified size, move position
//! above maximal value, write internal data above maximal size. Any read above
//! specified size or maximal length are legal and causes read zeroes.
//!
//! ### Examples and other crates.
//!
//! Example machines in `infmachine_examples`. Toolkit to create machines is `infmachine_gen`.
//! Executor and debugger of machines is `infmachine_exec`.

// InfParMachine cycle stages:
// 1. Circuit execution and handling internal data.
// 1.1. Fetch read memory cells to circuit input.
// 1.2. Fetch internal datas.
// 1.3. Execute circuit.
// 1.4. Process read/write of internal data.
// 1.5. Process position of internal data.
// 2. Read memory.
// 3. Clear memory to write.
// 4. Write memory and stop machine if needed.
// Write to memory done in all cycles of execution including last cycle with STOP_MACHINE=1.
// Write to memory not done in cycle with ILLEGAL_STATE=1 even if STOP_MACHINE=1.

pub mod proc_int_data;
use proc_int_data::*;
pub mod cycle_stage;
use cycle_stage::*;
mod circuit_config;
use circuit_config::*;

use gatenative::cpu_build_exec::*;
use gatenative::cpu_data_transform::*;

use gatenative::opencl_build_exec::*;
use gatenative::opencl_data_transform::*;
use gatenative::*;
use gatesim::*;
use infmachine_config::*;

pub use gatenative;
use gatenative::gatesim;
pub use infmachine_config;

use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
use std::str::FromStr;

// Internals:
// Buffer structure:
// [MACHINE_STATE, INTERNAL_DATA]
// MACHINE_STATE - main machine state. If stopped, if illegal state.
//   block is aligned to 256-byte boundary.
//   0 byte - stop or illegal state
//     0 bit - stop (only if machine normally stopped)
//     1 bit - illegal state
// INTERNAL_DATA - internal data. Entry for every processor. Entry structure:
//   [MEM_ADDRESS, TEMP_BUFFER, MEM_ADDRESS_POS, TEMP_BUFFER_POS, PROC_ID_POS,
//    READ_MEMCELL, WRITE_MEMCELL, READ_DATAPART, WRITE_DATAPART, MEMRW, DATAPART_RW,
//    DATAPART_MOVE_DIR, DATA_KIND, STOP_MACHINE, DATAPART_MOVE_DONE]
//   MEM_ADDRESS, TEMP_BUFFER - memory address and temporary buffer
//   MEM_ADDRESS_POS, TEMP_BUFFER_POS and PROC_ID_POS - position in these internal data.
//   READ_MEMCELL - read memory cell's value.
//   WRITE_MEMCELL - memory cell's value to write.
//   MEMRW - memory access bits
//   READ_DATAPART- read datapart's value.
//   WRITE_DATAPART - datapart's value to write.
//   DATAPART_RW - data part access bits
//   DATAPART_MOVE_DONE - 1-bit. if 1 then position of part changed.
//   STOP_MACHINE - if 1 then machine going to be stopped.
//   MEM_ADDRESS, TEMP_BUFFER are aligned to 4-byte boundary internally.
//   MEM_ADDRESS_POS andPROC_ID_POS have length of 1 byte and aligned to 1-byte.
//   TEMP_BUFFER_POS have length 2 bytes and aligned to 1-byte.
//   READ_MEMCELL are aligned to size-boundary or 4-byte boundary internally.
//   WRITE_MEMCELL are aligned to size-boundary internally.
//   READ_DATAPART are aligned to size-boundary or 4-byte boundary internally.
//   rest of fields are not aligned and can be packed to last dword in READ_DATAPART.
//   All entries are aligned to 4-byte boundary.
//
// Populated circuit inputs: all.
// Aggregated circuit outputs: all.
//
// IDEA to (API) interface: Add object to access internal data structures not by conversion,
// but handling internal data format in flow.

/// Data access to some internal data or main memory.
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DataAccess {
    /// Do nothing. No operation.
    Nothing,
    /// Make only read.
    ReadOnly,
    /// Make only write.
    WriteOnly,
    /// Read first and write later.
    ReadWrite,
}

/// Move of position of internal data.
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DataPartMove {
    /// No move.
    Nothing,
    /// Move 1 position forward.
    Forward,
    /// Move 1 position backward.
    Backward,
}

/// Internal data kind.
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DataKind {
    /// Memory address (`mem_address`).
    MemAddress,
    /// Temporary buffer (`temp_buffer`).
    TempBuffer,
    /// Processor's id (`proc_id`).
    ProcId,
}

/// Global state value if machine stopped with correct state.
pub(crate) const GLOBAL_STATE_STOP: u32 = 1;
/// Global state value if machine stopped with illegal state.
pub(crate) const GLOBAL_STATE_ILLEGAL: u32 = 2;

/// Error of machine caused by gatenative that circuit simulation.
#[derive(thiserror::Error, Debug)]
pub enum InfParMachineError<'a, DR, DW, D, E, CS>
where
    DR: DataReader,
    DW: DataWriter,
    D: DataHolder<'a, DR, DW>,
    E: Executor<'a, DR, DW, D>,
    E::ErrorType: Debug,
    CS: CycleStage<'a, DR, DW, D, E>,
    CS::ErrorType: Debug,
{
    /// If error occurred in some cycle stage.
    #[error("CycleStage: {0:?}")]
    CycleStage(CS::ErrorType),
    /// If error occurred in same circuit executor.
    #[error("Executor: {0:?}")]
    Executor(E::ErrorType),
}

/// Generic machine object.
///
/// This structure holds all objects to debug and run machine. It contains configuration,
/// executors, cycle stage executors, memories, internal states and internal data.
/// Thanks traits it possible to create machine that uses any `gatenative` executors.
/// Main traits are E - executor, CS - cycle stage executor, D - data holder.
pub struct InfParMachine<'a, DR, DW, D, E, CS, IDT, ODT>
where
    DR: DataReader,
    DW: DataWriter,
    D: DataHolder<'a, DR, DW>,
    E: Executor<'a, DR, DW, D> + DataTransforms<'a, DR, DW, D, IDT, ODT>,
    <E as Executor<'a, DR, DW, D>>::ErrorType: Debug,
    <E as DataTransforms<'a, DR, DW, D, IDT, ODT>>::ErrorType: Debug,
    CS: CycleStage<'a, DR, DW, D, E>,
    CS::ErrorType: Debug,
    IDT: DataTransformer<'a, DR, DW, D>,
    IDT::ErrorType: Debug,
    ODT: DataTransformer<'a, DR, DW, D>,
    ODT::ErrorType: Debug,
{
    exec_word_len: u32,
    config: InfParMachineConfig,
    env_config: InfParEnvConfig,
    int_states_tx: ODT,
    executor: E,
    cycle_stage: CS,
    int_states: D,
    int_state_len: u32,
    pidc: ProcIntDataConfig,
    proc_ints: D,
    memory: D,
    memory_last_mask: u32,
    cycle_no: u64,
    cycle_stage_no: u32,
    state: u32,
    pdr: PhantomData<&'a DR>,
    pdw: PhantomData<&'a DW>,
    podt: PhantomData<&'a IDT>,
}

impl<'a, DR, DW, D, E, CS, IDT, ODT> InfParMachine<'a, DR, DW, D, E, CS, IDT, ODT>
where
    DR: DataReader,
    DW: DataWriter,
    D: DataHolder<'a, DR, DW> + RangedData,
    E: Executor<'a, DR, DW, D> + DataTransforms<'a, DR, DW, D, IDT, ODT>,
    <E as Executor<'a, DR, DW, D>>::ErrorType: Debug,
    <E as DataTransforms<'a, DR, DW, D, IDT, ODT>>::ErrorType: Debug,
    CS: CycleStage<'a, DR, DW, D, E>,
    CS::ErrorType: Debug,
    IDT: DataTransformer<'a, DR, DW, D>,
    IDT::ErrorType: Debug,
    ODT: DataTransformer<'a, DR, DW, D>,
    ODT::ErrorType: Debug,
{
    /// Create new machine. `builder` is `gatenative` builder, `config` is
    /// machine configuration, `env_config` is environment configuration
    /// and circuit is machine circuit.
    pub fn new<B, T>(
        builder: B,
        config: InfParMachineConfig,
        env_config: InfParEnvConfig,
        circuit: Circuit<T>,
    ) -> Result<Self, B::ErrorType>
    where
        B: Builder<'a, DR, DW, D, E>,
        B::ErrorType: Debug,
        T: Clone + Copy + Ord + PartialEq + Eq + Hash,
        T: Default + TryFrom<usize>,
        <T as TryFrom<usize>>::Error: Debug,
        usize: TryFrom<T>,
        <usize as TryFrom<T>>::Error: Debug,
    {
        config.valid().unwrap();
        env_config.valid().unwrap();
        assert!(env_config.flat_memory, "Need flat memory model");
        assert!(env_config.max_mem_size.is_some());
        assert_ne!(env_config.max_mem_size.unwrap(), 0);
        let exec_word_len = builder.word_len();
        let circuit_input_len = usize::try_from(circuit.input_len()).unwrap();
        let state_len =
            circuit_input_len - (1 << config.cell_len_bits) - config.data_part_len as usize - 1;
        assert_eq!(state_len, config.state_len as usize);
        assert_eq!(circuit.outputs().len(), circuit_input_len + 8);
        let memory_size: usize = env_config.max_mem_size.unwrap().try_into().unwrap();
        let proc_num_usize: usize = env_config.proc_num.try_into().unwrap();
        let pidc = ProcIntDataConfig::new(config, env_config);
        let mut exec = build_circuit(builder, circuit, &pidc, proc_num_usize)?;
        let cycle_stage = CS::new_from_executor(&exec, config, env_config);
        let int_states = exec.new_data_input_elems(proc_num_usize);
        let proc_ints = exec.new_data(64 + pidc.len() * proc_num_usize);
        let memory = exec.new_data((memory_size + 3) >> 2);
        let int_states_tx = exec
            .output_transformer((state_len + 31) & !31, &(0..state_len).collect::<Vec<_>>())
            .unwrap();
        Ok(Self {
            exec_word_len,
            config,
            env_config,
            int_states_tx,
            executor: exec,
            cycle_stage,
            int_states,
            int_state_len: u32::try_from(state_len).unwrap(),
            pidc,
            proc_ints,
            memory,
            memory_last_mask: if (memory_size & 3) != 0 {
                (1u32 << ((memory_size & 3) * 8)) - 1u32
            } else {
                u32::MAX
            },
            cycle_no: 0,
            cycle_stage_no: 0,
            state: 0,
            pdr: PhantomData,
            pdw: PhantomData,
            podt: PhantomData,
        })
    }
    /// Create new machine from data. `builder` is `gatenative` builder, `data` is
    /// machine configuration data and its circuit.
    pub fn new_from_data<B, T>(builder: B, data: InfParMachineData<T>) -> Result<Self, B::ErrorType>
    where
        B: Builder<'a, DR, DW, D, E>,
        B::ErrorType: Debug,
        T: Clone + Copy + Ord + Debug + PartialEq + Eq + Hash + std::ops::Add<Output = T>,
        T: FromStr + From<u8>,
        <T as FromStr>::Err: Debug,
        T: Default + TryFrom<usize>,
        <T as TryFrom<usize>>::Error: Debug,
        usize: TryFrom<T>,
        <usize as TryFrom<T>>::Error: Debug,
    {
        Self::new(builder, data.config, data.env_config, data.circuit)
    }

    /// Initializes machine. It initializes main memory and internal states of all processors.
    pub fn initialize(&mut self) {
        self.initialize_state();
        self.memory.fill(0);
    }

    // Initializes internal states of processors.
    pub fn initialize_state(&mut self) {
        self.int_states.fill(0);
        self.proc_ints.fill(0);
        self.cycle_no = 0;
        self.cycle_stage_no = 0;
        self.state = 0;
    }

    /// Executes machine. A machine going to stop if STOP_MACHINE set in any processor or
    /// some illegal state occurred in any processor.
    /// If STOP_MACHINE or illegal state already happened then no execution.
    /// Returns total number of cycles that machine executes.
    pub fn execute(&mut self) -> Result<u64, InfParMachineError<'a, DR, DW, D, E, CS>> {
        while self.state == 0 {
            self.execute_cycle()?;
        }
        Ok(self.cycle_no)
    }

    /// Executes machine. Executes only specified number of cycles.
    /// A machine going to stop if STOP_MACHINE set in any processor or
    /// some illegal state occurred in any processor.
    /// If STOP_MACHINE or illegal state already happened then no execution.
    /// Returns total number of cycles that machine executes.
    pub fn execute_cycles(
        &mut self,
        cycles: u64,
    ) -> Result<u64, InfParMachineError<'a, DR, DW, D, E, CS>> {
        for _ in 0..cycles {
            if self.state != 0 {
                break;
            }
            self.execute_cycle()?;
        }
        Ok(self.cycle_no)
    }

    /// Executes single cycle of machine.
    /// A machine going to stop if STOP_MACHINE set in any processor or
    /// some illegal state occurred in any processor.
    /// If STOP_MACHINE or illegal state already happened then no execution.
    /// Returns total number of cycles that machine executes.
    pub fn execute_cycle(&mut self) -> Result<u64, InfParMachineError<'a, DR, DW, D, E, CS>> {
        if self.state == 0 {
            for _ in self.cycle_stage_no..4 {
                self.execute_cycle_stage()?;
                if (self.state & GLOBAL_STATE_ILLEGAL) != 0 {
                    break;
                }
            }
        }
        Ok(self.cycle_no)
    }

    /// Executes single cycle stage of machine.
    /// A machine going to stop if STOP_MACHINE set in any processor or
    /// some illegal state occurred in any processor.
    /// If illegal state already happened then no execution.
    /// If STOP_MACHINE alreadu happened then only cycle stage in current cycle
    /// going to be executed.
    /// Returns total number of cycles that machine executes and next cycle stage.
    pub fn execute_cycle_stage(
        &mut self,
    ) -> Result<(u64, u32), InfParMachineError<'a, DR, DW, D, E, CS>> {
        if (self.state & GLOBAL_STATE_ILLEGAL) == 0
            && ((self.state & GLOBAL_STATE_STOP) == 0 || self.cycle_stage_no != 0)
        {
            match self.cycle_stage_no {
                0 => {
                    self.executor
                        .execute_buffer_single(&mut self.int_states, 0, &mut self.proc_ints)
                        .map_err(|e| InfParMachineError::Executor(e))?;
                }
                1 => {
                    self.cycle_stage
                        .execute_read(&mut self.proc_ints, &self.memory)
                        .map_err(|e| InfParMachineError::CycleStage(e))?;
                }
                2 => {
                    self.cycle_stage
                        .execute_clear(&mut self.proc_ints, &mut self.memory)
                        .map_err(|e| InfParMachineError::CycleStage(e))?;
                }
                3 => {
                    self.cycle_stage
                        .execute_write(&mut self.proc_ints, &mut self.memory)
                        .map_err(|e| InfParMachineError::CycleStage(e))?;
                }
                _ => {
                    panic!("Unexpected!");
                }
            }
            self.cycle_stage_no = if self.cycle_stage_no == 3 {
                self.cycle_no += 1;
                0
            } else {
                self.cycle_stage_no + 1
            };
            // read machine state
            let old_len = self.proc_ints.len();
            self.proc_ints.set_range(0..1);
            self.state = self.proc_ints.process(|d| d[0]);
            self.proc_ints.set_range(0..old_len);
        }
        Ok((self.cycle_no, self.cycle_stage_no))
    }

    /// Returns number of processors of machine.
    pub fn proc_num(&self) -> u64 {
        self.env_config.proc_num
    }

    /// Returns main memory size of machine in bytes.
    pub fn memory_size(&self) -> u64 {
        self.env_config.max_mem_size.unwrap()
    }

    /// Returns configuration.
    pub fn config(&self) -> &InfParMachineConfig {
        &self.config
    }

    /// Returns environment configuration.
    pub fn env_config(&self) -> &InfParEnvConfig {
        &self.env_config
    }

    /// Returns total number of executed cycles.
    pub fn cycle_no(&self) -> u64 {
        self.cycle_no
    }

    /// Returns current cycle stage.
    pub fn cycle_stage_no(&self) -> u32 {
        self.cycle_stage_no
    }

    /// Returns internal state length in bits.
    pub fn state_len(&self) -> u32 {
        self.int_state_len
    }

    /// Reads main memory of machine. Units are 32-bit words (dwords).
    /// `start` specifies first memory word, `end` specifies word after reading.
    /// Returns vector of 32-bit words.
    pub fn read_memory(&mut self, start: u64, end: u64) -> Vec<u32> {
        let start = usize::try_from(start).unwrap();
        let end = usize::try_from(end).unwrap();
        let mem_length = self.memory.len();
        assert!(start <= mem_length);
        assert!(end <= mem_length);
        self.memory.set_range(start..end);
        let mut out = vec![0; end - start];
        self.memory.process(|d| {
            out.copy_from_slice(d);
            if end == mem_length {
                // fix for last memory bytes
                *out.last_mut().unwrap() &= self.memory_last_mask;
            }
        });
        self.memory.set_range(0..mem_length);
        out
    }

    /// Writes main memory of machine. Units are 32-bit words (dwords).
    /// `start` specifies first memory word.
    /// Returns `src` is slice of 32-bit words.
    pub fn write_memory(&mut self, start: u64, src: &[u32]) {
        let start = usize::try_from(start).unwrap();
        let mem_length = self.memory.len();
        let end = start + src.len();
        assert!(start <= mem_length);
        assert!(end <= mem_length);
        self.memory.set_range(start..end);
        self.memory.process_mut(|d| {
            d.copy_from_slice(src);
            if end == mem_length {
                // fix for last memory bytes
                d[end - start - 1] &= self.memory_last_mask;
            }
        });
        self.memory.set_range(0..mem_length);
    }

    /// Reads main memory of machine. Units are bytes and `start` and `end` must be
    /// aligned to 4 (32-bit words).
    /// `start` specifies first memory byte, `end` specifies byte after reading.
    /// Returns vector of bytes.
    pub fn read_memory_bytes(&mut self, start: u64, end: u64) -> Vec<u8> {
        let start = usize::try_from(start).unwrap();
        let end = usize::try_from(end).unwrap();
        assert_eq!(start & 3, 0);
        assert_eq!(end & 3, 0);
        let start = start >> 2;
        let end = end >> 2;
        let mem_length = self.memory.len();
        assert!(start <= mem_length);
        assert!(end <= mem_length);
        self.memory.set_range(start..end);
        let mut out = vec![0u8; (end << 2) - (start << 2)];
        self.memory.process(|d| {
            for (i, v) in d.iter().enumerate() {
                let vb = v.to_ne_bytes();
                out[i << 2] = vb[0];
                out[(i << 2) + 1] = vb[1];
                out[(i << 2) + 2] = vb[2];
                out[(i << 2) + 3] = vb[3];
            }
            if end == mem_length {
                // fix for last memory bytes
                let i = end - start - 1;
                let vb = self.memory_last_mask.to_ne_bytes();
                out[i << 2] &= vb[0];
                out[(i << 2) + 1] &= vb[1];
                out[(i << 2) + 2] &= vb[2];
                out[(i << 2) + 3] &= vb[3];
            }
        });
        self.memory.set_range(0..mem_length);
        out
    }

    /// Writes main memory of machine. Units are bytes and `start and length of `src` must be
    /// aligned to 4 (32-bit words).
    /// `start` specifies first memory word.
    /// Returns `src` is slice of bytes.
    pub fn write_memory_bytes(&mut self, start: u64, src: &[u8]) {
        let start = usize::try_from(start).unwrap();
        let end = start + src.len();
        assert_eq!(start & 3, 0);
        assert_eq!(end & 3, 0);
        let start = start >> 2;
        let end = end >> 2;
        let mem_length = self.memory.len();
        assert!(start <= mem_length);
        assert!(end <= mem_length);
        self.memory.set_range(start..end);
        self.memory.process_mut(|d| {
            for (i, v) in d.iter_mut().enumerate() {
                let s = [
                    src[i << 2],
                    src[(i << 2) + 1],
                    src[(i << 2) + 2],
                    src[(i << 2) + 3],
                ];
                *v = u32::from_ne_bytes(s);
            }
            if end == mem_length {
                // fix for last memory bytes
                d[end - start - 1] &= self.memory_last_mask;
            }
        });
        self.memory.set_range(0..mem_length);
    }

    /// Gets states of processors. `start` and `end` are processor's ids.
    /// Returns vector of 32-bit words and length of single processor's state in
    /// 32-bit words.
    pub fn states(&mut self, start: u64, end: u64) -> (Vec<u32>, u32) {
        let start: usize = start.try_into().unwrap();
        let end: usize = end.try_into().unwrap();
        let exec_word_len_usize = self.exec_word_len as usize;
        let state_len_in_dwords = ((self.int_state_len + 31) >> 5) as usize;
        let start_w: usize = (start / exec_word_len_usize).try_into().unwrap();
        let end_w: usize = ((end + exec_word_len_usize - 1) / exec_word_len_usize)
            .try_into()
            .unwrap();
        let int_all_states_len = self.int_states.len();
        let start_w2 = start_w * (self.int_state_len as usize) * (exec_word_len_usize >> 5);
        let end_w2 = end_w * (self.int_state_len as usize) * (exec_word_len_usize >> 5);
        self.int_states.set_range(start_w2..end_w2);
        let data = self.int_states_tx.transform(&self.int_states).unwrap();
        let out = data.process(|d| {
            let mut out = vec![0; ((end - start) as usize) * state_len_in_dwords];
            out.copy_from_slice(
                &d[((start as usize) - start_w * exec_word_len_usize) * state_len_in_dwords
                    ..((end as usize) - start_w * exec_word_len_usize) * state_len_in_dwords],
            );
            out
        });
        self.int_states.set_range(0..int_all_states_len);
        (out, state_len_in_dwords as u32)
    }

    /// Gets `proc_int_data` (internal processor state).`start` and `end` are processor's ids.
    /// Returns reader that allow to read states.
    pub fn proc_int_data(&mut self, start: u64, end: u64) -> ProcIntDataReader {
        assert!(start <= self.env_config.proc_num);
        assert!(end <= self.env_config.proc_num);
        let start: usize = start.try_into().unwrap();
        let end: usize = end.try_into().unwrap();
        let entry_len = self.pidc.len();
        let proc_ints_len = self.proc_ints.len();
        self.proc_ints
            .set_range(64 + start * entry_len..64 + end * entry_len);
        let pidr = self
            .proc_ints
            .process(|d| ProcIntDataReader::new_from_config(self.pidc, d.to_vec()));
        self.proc_ints.set_range(0..proc_ints_len);
        pidr
    }

    /// Returns true if machine stopped.
    pub fn stopped(&self) -> bool {
        (self.state & GLOBAL_STATE_STOP) != 0
    }

    /// Returns true if machine in illegal state.
    pub fn illegal_state(&self) -> bool {
        (self.state & GLOBAL_STATE_ILLEGAL) != 0
    }
}

/// Type of CPU infinite machine to run at CPU.
pub type CPUInfParMachine<'a> = InfParMachine<
    'a,
    CPUDataReader<'a>,
    CPUDataWriter<'a>,
    CPUDataHolder,
    CPUExecutor,
    CPUCycleStage,
    CPUDataInputTransformer,
    CPUDataOutputTransformer,
>;

/// Type of CPU infinite machine to run at OpenCL devices.
pub type OpenCLInfParMachine<'a> = InfParMachine<
    'a,
    OpenCLDataReader<'a>,
    OpenCLDataWriter<'a>,
    OpenCLDataHolder,
    OpenCLExecutor,
    OpenCLCycleStage,
    OpenCLDataInputTransformer,
    OpenCLDataOutputTransformer,
>;

#[cfg(test)]
mod tests {
    use super::*;

    use gatenative::clang_writer::*;

    #[test]
    fn test_infparmachine() {
        let builder = CPUBuilder::new_with_cpu_ext_and_clang_config(
            CPUExtension::NoExtension,
            &CLANG_WRITER_U64,
            None,
        );
        let config = InfParMachineConfig {
            state_len: 44,
            data_part_len: 32,
            cell_len_bits: 5,
        };
        let env_config = InfParEnvConfig {
            proc_num: 64 * 1024,
            flat_memory: true,
            max_temp_buffer_len: 96,
            max_mem_size: Some(400 * 1024),
        };
        let pic = ProcIntDataConfig::new(config, env_config);
        println!("EntryLen: {}", pic.len());
        let mem_cell_data_part_len = (1 << config.cell_len_bits) + config.data_part_len;
        let circuit_input_len = config.state_len + mem_cell_data_part_len + 1;
        let circuit = Circuit::<u32>::new(
            circuit_input_len,
            [Gate::new_nor(0, circuit_input_len - 1)],
            std::iter::once((circuit_input_len, true)).chain(
                (1..circuit_input_len - 1)
                    .chain(0..9)
                    .map(|i| (i, i >= config.state_len && i < circuit_input_len - 1)),
            ),
        )
        .unwrap();
        let mut machine =
            CPUInfParMachine::<'_>::new(builder, config, env_config, circuit).unwrap();
        assert_eq!(machine.proc_num(), 64 * 1024);
        {
            // write some data to memory
            let mut mem = machine.memory.get_mut();
            let mem = mem.get_mut();
            for i in 0..100 {
                mem[4421 + i] = 532566 + 6 * u32::try_from(i).unwrap();
            }
            for i in 0..200 {
                mem[46969 + i] = 0xddaa00 + 7 * u32::try_from(i).unwrap();
            }
            mem[100 * 1024 - 1] = 0xaa22cc77;
        }
        // test memory reading
        assert_eq!(
            (0..100).map(|i| 532566 + 6 * i).collect::<Vec<_>>(),
            machine.read_memory(4421, 4421 + 100),
        );
        assert_eq!(
            (0..200).map(|i| 0xddaa00 + 7 * i).collect::<Vec<_>>(),
            machine.read_memory(46969, 46969 + 200),
        );
        assert_eq!(
            vec![0, 0xaa22cc77],
            machine.read_memory(100 * 1024 - 2, 100 * 1024),
        );
        // test memory reading by bytes
        assert_eq!(
            (0..100)
                .map(|i| (532566u32 + 6 * i).to_ne_bytes())
                .flatten()
                .collect::<Vec<_>>(),
            machine.read_memory_bytes(4 * 4421, 4 * (4421 + 100)),
        );
        assert_eq!(
            (0..200)
                .map(|i| (0xddaa00u32 + 7 * i).to_ne_bytes())
                .flatten()
                .collect::<Vec<_>>(),
            machine.read_memory_bytes(4 * 46969, 4 * (46969 + 200)),
        );
        assert_eq!(
            0xaa22cc77u32.to_ne_bytes().to_vec(),
            machine.read_memory_bytes(4 * (100 * 1024 - 1), 4 * 100 * 1024),
        );
        // test memory writing
        machine.write_memory(4500, &(0..200).map(|i| 244211 + 10 * i).collect::<Vec<_>>());
        {
            let mem = machine.memory.get();
            let mem = mem.get();
            assert_eq!(
                (0..200).map(|i| 244211 + 10 * i).collect::<Vec<_>>(),
                &mem[4500..4500 + 200]
            );
        }
        // test memory writing by bytes
        machine.write_memory_bytes(
            4 * 4500,
            &(0..200)
                .map(|i| (244277u32 + 9 * i).to_ne_bytes())
                .flatten()
                .collect::<Vec<_>>(),
        );
        {
            let mem = machine.memory.get();
            let mem = mem.get();
            assert_eq!(
                (0..200).map(|i| 244277 + 9 * i).collect::<Vec<_>>(),
                &mem[4500..4500 + 200]
            );
        }
        // test reading states
        let mut it = machine
            .executor
            .input_transformer(
                ((config.state_len + 31) & !31) as usize,
                &(0..config.state_len)
                    .map(|i| i as usize)
                    .collect::<Vec<_>>(),
            )
            .unwrap();
        let states_data = machine.executor.new_data_from_vec(
            (0..4096)
                .map(|i| [0x677da3b + 5 * i, (0x545a44 + 3 * i) & 0xfff])
                .flatten()
                .collect::<Vec<_>>(),
        );
        let states_data = it.transform(&states_data).unwrap();
        {
            let mut int_states = machine.int_states.get_mut();
            let int_states = int_states.get_mut();
            let states_data = states_data.get();
            let states_data = states_data.get();
            // (4096/32*44)/8 -> 704.
            int_states[14 * 704 * 2..(14 + 4) * 704 * 2].copy_from_slice(&states_data);
        }
        // first read
        let (states, state_len) = machine.states(14 * 1024, 18 * 1024);
        assert_eq!(2, state_len);
        assert_eq!(2 * 4096, states.len());
        for i in 0..4096 {
            let j = u32::try_from(i).unwrap();
            assert_eq!(
                &states[2 * i..2 * i + 2],
                [0x677da3b + 5 * j, (0x545a44 + 3 * j) & 0xfff],
                "{}",
                i
            );
        }
        // second read
        let (states, state_len) = machine.states(14 * 1024 + 21, 18 * 1024 - 7);
        assert_eq!(2, state_len);
        assert_eq!(2 * (4096 - 21 - 7), states.len());
        for i in 21..4096 - 7 {
            let j = u32::try_from(i).unwrap();
            assert_eq!(
                &states[2 * (i - 21)..2 * (i - 21) + 2],
                [0x677da3b + 5 * j, (0x545a44 + 3 * j) & 0xfff],
                "{}",
                i
            );
        }
        // third read
        let (states, state_len) = machine.states(14 * 1024 + 20, 18 * 1024 - 32 + 11);
        assert_eq!(2, state_len);
        assert_eq!(2 * (4096 - 20 - 32 + 11), states.len());
        for i in 20..4096 - 32 + 11 {
            let j = u32::try_from(i).unwrap();
            assert_eq!(
                &states[2 * (i - 20)..2 * (i - 20) + 2],
                [0x677da3b + 5 * j, (0x545a44 + 3 * j) & 0xfff],
                "{}",
                i
            );
        }
        // read 4
        let (states, state_len) = machine.states(14 * 1024 + 47, 18 * 1024 - 64 + 13);
        assert_eq!(2, state_len);
        assert_eq!(2 * (4096 - 47 - 64 + 13), states.len());
        for i in 47..4096 - 64 + 13 {
            let j = u32::try_from(i).unwrap();
            assert_eq!(
                &states[2 * (i - 47)..2 * (i - 47) + 2],
                [0x677da3b + 5 * j, (0x545a44 + 3 * j) & 0xfff],
                "{}",
                i
            );
        }
        // test reading proc_int_data
        {
            let mut pidata = machine.proc_ints.get_mut();
            let pidata = pidata.get_mut();
            let entry_len = pic.len();
            for i in 0..10 {
                let j = u32::try_from(i).unwrap();
                pidata[64 + (120 + i) * entry_len] = 0xada355 + j;
                pidata[64 + (120 + i) * entry_len + 1] = 0x2a78 + j;
            }
        }
        let pidr = machine.proc_int_data(120, 130);
        for i in 0..10u64 {
            let j = u32::try_from(i).unwrap();
            assert_eq!(0xada355 + u64::from(j), pic.mem_address(&pidr[i]));
            assert_eq!(vec![0x2a78 + j, 0, 0], pic.temp_buffer(&pidr[i]));
        }
        //
        // next machine with odd memory size
        let builder = CPUBuilder::new_with_cpu_ext_and_clang_config(
            CPUExtension::NoExtension,
            &CLANG_WRITER_U64,
            None,
        );
        let env_config = InfParEnvConfig {
            proc_num: 64 * 1024,
            flat_memory: true,
            max_temp_buffer_len: 96,
            max_mem_size: Some(400 * 1024 - 3),
        };
        let pic = ProcIntDataConfig::new(config, env_config);
        println!("EntryLen: {}", pic.len());
        let mem_cell_data_part_len = (1 << config.cell_len_bits) + config.data_part_len;
        let circuit_input_len = config.state_len + mem_cell_data_part_len + 1;
        let circuit = Circuit::<u32>::new(
            circuit_input_len,
            [Gate::new_nor(0, circuit_input_len - 1)],
            std::iter::once((circuit_input_len, true)).chain(
                (1..circuit_input_len - 1)
                    .chain(0..9)
                    .map(|i| (i, i >= config.state_len && i < circuit_input_len - 1)),
            ),
        )
        .unwrap();
        let mut machine =
            CPUInfParMachine::<'_>::new(builder, config, env_config, circuit).unwrap();
        // test writing at end of memory random value to get cut value.
        {
            // write some data to memory
            let mut mem = machine.memory.get_mut();
            let mem = mem.get_mut();
            mem[100 * 1024 - 1] = 0xaa22cc77;
        }
        assert_eq!(
            vec![0, 0x77],
            machine.read_memory(100 * 1024 - 2, 100 * 1024),
        );
        assert_eq!(
            0x77u32.to_ne_bytes().to_vec(),
            machine.read_memory_bytes(4 * (100 * 1024 - 1), 4 * 100 * 1024),
        );
        // test memory writing
        machine.write_memory(100 * 1024 - 2, &[0, 0xab348a]);
        {
            let mem = machine.memory.get();
            let mem = mem.get();
            assert_eq!(vec![0, 0x8a], &mem[100 * 1024 - 2..]);
        }
        // test memory writing bytes
        machine.write_memory_bytes(4 * (100 * 1024 - 1), &[0x5e, 0x11, 0x22, 0x33]);
        {
            let mem = machine.memory.get();
            let mem = mem.get();
            assert_eq!(vec![0, 0x5e], &mem[100 * 1024 - 2..]);
        }
    }
}