1 module gbaid.gba.sio; 2 3 import gbaid.util; 4 5 import gbaid.gba.io; 6 import gbaid.gba.interrupt; 7 8 public enum CommunicationState { 9 IDLE, 10 WRITE_DONE, 11 READ_DONE, 12 FINALIZE_DONE 13 } 14 15 public interface Communication { 16 public CommunicationState getState(); 17 public void setReady(uint index, bool ready); 18 public bool allReady(); 19 20 public void init(); 21 22 public void readDone(uint index, bool done); 23 public bool readDone(uint index); 24 25 public void finalizeDone(uint index, bool done); 26 public bool finalizeDone(uint index); 27 28 public void deinit(); 29 30 public uint read(uint index); 31 public void write(uint index, uint data); 32 } 33 34 private enum IoMode { 35 NORMAL_8BIT, NORMAL_32BIT, MULTIPLAYER, UART, JOYBUS, GENERAL_PURPOSE 36 } 37 38 private struct MultiplayerControl { 39 private byte baudRate = 0; 40 private bool child = false; 41 private bool allReady = false; 42 private byte id = 0; 43 private bool error = false; 44 private bool active = false; 45 private bool interrupt = false; 46 } 47 48 public class SerialPort { 49 private InterruptHandler interruptHandler; 50 private Communication _communication; 51 private MultiplayerControl control; 52 private int data1 = 0; 53 private int data2 = 0; 54 private short data3 = 0; 55 private bool stateSc = false, stateSd = false, stateSi = false, stateSo = false; 56 private bool dirSc = false, dirSd = false, dirSi = false, dirSo = false; 57 private bool interruptSi = false; 58 private byte mode1 = 0; 59 private byte mode2 = 0; 60 private uint index = 0; 61 private size_t waitCycles = 0; 62 63 public this(IoRegisters* ioRegisters, InterruptHandler interruptHandler, uint index) { 64 this.interruptHandler = interruptHandler; 65 66 this.index = index; 67 control.child = index != 0; 68 69 _communication = new NullCommunication(); 70 71 ioRegisters.mapAddress(0x128, &control.baudRate, 0b11, 0); 72 ioRegisters.mapAddress(0x128, &control.child, 0b1, 2, true, false); 73 ioRegisters.mapAddress(0x128, &control.allReady, 0b1, 3, true, false); 74 ioRegisters.mapAddress(0x128, &control.id, 0b11, 4, true, false); 75 ioRegisters.mapAddress(0x128, &control.error, 0b1, 6, true, false); 76 ioRegisters.mapAddress(0x128, &control.active, 0b1, 7, true, index == 0).postWriteMonitor(&onPostWriteActive); 77 ioRegisters.mapAddress(0x128, &control.interrupt, 0b1, 14); 78 79 ioRegisters.mapAddress(0x120, &data1, 0xFFFFFFFF, 0); 80 ioRegisters.mapAddress(0x124, &data2, 0xFFFFFFFF, 0); 81 ioRegisters.mapAddress(0x128, &data3, 0xFFFF, 16).postWriteMonitor(&onPostWriteOutData); 82 83 ioRegisters.mapAddress(0x134, &stateSc, 0b1, 0); 84 ioRegisters.mapAddress(0x134, &stateSd, 0b1, 1); 85 ioRegisters.mapAddress(0x134, &stateSi, 0b1, 2); 86 ioRegisters.mapAddress(0x134, &stateSo, 0b1, 3); 87 ioRegisters.mapAddress(0x134, &dirSc, 0b1, 4); 88 ioRegisters.mapAddress(0x134, &dirSd, 0b1, 5); 89 ioRegisters.mapAddress(0x134, &dirSi, 0b1, 6); 90 ioRegisters.mapAddress(0x134, &dirSo, 0b1, 7); 91 ioRegisters.mapAddress(0x134, &interruptSi, 0b1, 8); 92 93 ioRegisters.mapAddress(0x128, &mode1, 0b11, 12).postWriteMonitor(&onPostWriteMode); 94 ioRegisters.mapAddress(0x134, &mode2, 0b11, 14).postWriteMonitor(&onPostWriteMode); 95 } 96 97 @property public void communication(Communication communication) { 98 _communication = communication; 99 } 100 101 private void onPostWriteMode(int mask, int oldValue, int newValue) { 102 if (oldValue == newValue) { 103 return; 104 } 105 _communication.setReady(index, ioMode == IoMode.MULTIPLAYER); 106 } 107 108 private void onPostWriteActive(int mask, int oldValue, int newValue) { 109 if (oldValue || !newValue) { 110 return; 111 } 112 if (ioMode == IoMode.MULTIPLAYER && index == 0) { 113 _communication.init(); 114 } 115 } 116 117 private void onPostWriteOutData(int mask, int oldValue, int newValue) { 118 _communication.write(index, data3); 119 } 120 121 public size_t emulate(size_t cycles) { 122 waitCycles += cycles; 123 124 if (ioMode != IoMode.MULTIPLAYER) { 125 return 0; 126 } 127 128 control.allReady = _communication.allReady(); 129 130 final switch (_communication.getState()) with (CommunicationState) { 131 case IDLE: 132 break; 133 case WRITE_DONE: { 134 if (!_communication.readDone(index)) { 135 data1.setBits(0, 15, _communication.read(0)); 136 data1.setBits(16, 31, _communication.read(1)); 137 data2.setBits(0, 15, _communication.read(2)); 138 data2.setBits(16, 31, _communication.read(3)); 139 140 _communication.readDone(index, true); 141 142 waitCycles = 0; 143 control.active = true; 144 } 145 break; 146 } 147 case READ_DONE: { 148 if (!_communication.finalizeDone(index) && waitCycles >= 1024) { 149 control.active = false; 150 control.id = cast(byte) index; 151 control.error = false; 152 153 if (control.interrupt) { 154 interruptHandler.requestInterrupt(InterruptSource.SERIAL_COMMUNICATION); 155 } 156 157 _communication.finalizeDone(index, true); 158 } 159 break; 160 } 161 case FINALIZE_DONE: { 162 if (index == 0) { 163 _communication.deinit(); 164 } 165 break; 166 } 167 } 168 169 return 0; 170 } 171 172 @property private IoMode ioMode() { 173 final switch (mode2) { 174 case 0b00: 175 case 0b01: { 176 final switch (mode1) { 177 case 0b00: 178 return IoMode.NORMAL_8BIT; 179 case 0b01: 180 return IoMode.NORMAL_32BIT; 181 case 0b10: 182 return IoMode.MULTIPLAYER; 183 case 0b11: 184 return IoMode.UART; 185 } 186 } 187 case 0b10: 188 return IoMode.GENERAL_PURPOSE; 189 case 0b11: 190 return IoMode.JOYBUS; 191 } 192 } 193 } 194 195 private class NullCommunication : Communication { 196 public override CommunicationState getState() { 197 return CommunicationState.IDLE; 198 } 199 200 public override void setReady(uint index, bool ready) { 201 } 202 203 public override bool allReady() { 204 return false; 205 } 206 207 public override void init() { 208 } 209 210 public override void readDone(uint index, bool done) { 211 } 212 213 public override bool readDone(uint index) { 214 return true; 215 } 216 217 public override void finalizeDone(uint index, bool done) { 218 } 219 220 public override bool finalizeDone(uint index) { 221 return true; 222 } 223 224 public void deinit() { 225 } 226 227 public override uint read(uint index) { 228 return 0xFFFFFFFF; 229 } 230 231 public override void write(uint index, uint data) { 232 } 233 }