1 module gbaid.comm;
2 
3 import core.atomic : MemoryOrder, atomicLoad, atomicStore, atomicOp;
4 
5 import gbaid.util;
6 
7 import gbaid.gba.sio : Communication, CommunicationState;
8 
9 public class SharedSerialData {
10     public shared uint[4] data;
11     /*
12         [0, 3] -> connected
13         [4, 7] -> ready
14         [8, 11] -> read
15         [12, 15] -> finalized
16         16 -> active
17     */
18     public shared uint status;
19 
20     this() {
21         data[] = 0xFFFFFFFF;
22         status = 0;
23     }
24 }
25 
26 public class MappedMemoryCommunication : Communication {
27     private uint index;
28     private SharedSerialData _shared;
29 
30     public this(uint index, SharedSerialData _shared) {
31         this.index = index;
32         this._shared = _shared;
33 
34         atomicOp!"|="(_shared.status, 1 << index);
35     }
36 
37     public ~this() {
38         atomicOp!"&="(_shared.status, ~(1 << index));
39         atomicStore!(MemoryOrder.raw)(_shared.data[index], 0xFFFFFFFF);
40     }
41 
42     public override CommunicationState getState() {
43         uint status = atomicLoad!(MemoryOrder.raw)(_shared.status);
44 
45         uint connected = status.getBits(0, 3);
46         bool allRead = status.getBits(8, 11) == connected;
47         bool allFinalized = status.getBits(12, 15) == connected;
48         bool active = status.checkBit(16);
49 
50         if (active && allRead && allFinalized) {
51             return CommunicationState.FINALIZE_DONE;
52         }
53         if (active && allRead) {
54             return CommunicationState.READ_DONE;
55         }
56         if (active) {
57             return CommunicationState.WRITE_DONE;
58         }
59         return CommunicationState.IDLE;
60     }
61 
62     public override void setReady(uint index, bool ready) {
63         if (ready) {
64             atomicOp!"|="(_shared.status, 0b10000 << index);
65         } else {
66             atomicOp!"&="(_shared.status, ~(0b1000100010000 << index));
67             atomicStore!(MemoryOrder.raw)(_shared.data[index], 0xFFFFFFFF);
68         }
69     }
70 
71     public override bool allReady() {
72         uint status = atomicLoad!(MemoryOrder.raw)(_shared.status);
73         uint connected = status.getBits(0, 3);
74         return status.getBits(4, 7) == connected;
75     }
76 
77     public override void init() {
78         atomicOp!"|="(_shared.status, 1 << 16);
79     }
80 
81     public override void readDone(uint index, bool done) {
82         atomicOp!"|="(_shared.status, 1 << index + 8);
83     }
84 
85     public override bool readDone(uint index) {
86         return atomicLoad!(MemoryOrder.raw)(_shared.status).checkBit(index + 8);
87     }
88 
89     public override void finalizeDone(uint index, bool done) {
90         atomicOp!"|="(_shared.status, 1 << index + 12);
91     }
92 
93     public override bool finalizeDone(uint index) {
94         return atomicLoad!(MemoryOrder.raw)(_shared.status).checkBit(index + 12);
95     }
96 
97     public override void deinit() {
98         atomicOp!"&="(_shared.status, ~0b11111111100000000);
99     }
100 
101     public override uint read(uint index) {
102         return atomicLoad!(MemoryOrder.raw)(_shared.data[index]);
103     }
104 
105     public override void write(uint index, uint word) {
106         atomicStore!(MemoryOrder.raw)(_shared.data[index], word);
107     }
108 }