1 module gbaid.gba.keypad; 2 3 import gbaid.util; 4 5 import gbaid.gba.io; 6 import gbaid.gba.interrupt; 7 import gbaid.gba.display : CYCLES_PER_FRAME; 8 9 public enum Button { 10 A = 0, 11 B = 1, 12 SELECT = 2, 13 START = 3, 14 RIGHT = 4, 15 LEFT = 5, 16 UP = 6, 17 DOWN = 7, 18 R = 8, 19 L = 9 20 } 21 22 private enum STATE_BITS_CLEARED = 0b1111111111; 23 24 public struct KeypadState { 25 private int bits = STATE_BITS_CLEARED; 26 27 public void clear() { 28 bits = STATE_BITS_CLEARED; 29 } 30 31 public bool isPressed(Button button) { 32 return !bits.checkBit(button); 33 } 34 35 public void setPressed(Button button, bool pressed = true) { 36 bits.setBit(button, !pressed); 37 } 38 39 public KeypadState opBinary(string op)(KeypadState that) if (op == "|") { 40 KeypadState combined; 41 combined.bits = this.bits & that.bits; 42 return combined; 43 } 44 45 public KeypadState opOpAssign(string op)(KeypadState that) if (op == "|") { 46 bits &= that.bits; 47 return this; 48 } 49 } 50 51 public class Keypad { 52 private InterruptHandler interruptHandler; 53 private ptrdiff_t cyclesUntilNextUpdate = 0; 54 private int stateBits = STATE_BITS_CLEARED; 55 private int control = 0; 56 57 public this(IoRegisters* ioRegisters, InterruptHandler interruptHandler) { 58 this.interruptHandler = interruptHandler; 59 60 ioRegisters.mapAddress(0x130, &stateBits, 0x3FF, 0, true, false); 61 ioRegisters.mapAddress(0x130, &control, 0xC3FF, 16); 62 } 63 64 public void setState(KeypadState state) { 65 stateBits = state.bits; 66 } 67 68 public size_t emulate(size_t cycles) { 69 cyclesUntilNextUpdate -= cycles; 70 if (cyclesUntilNextUpdate > 0) { 71 return 0; 72 } 73 cyclesUntilNextUpdate += CYCLES_PER_FRAME; 74 if (control.checkBit(14)) { 75 auto pressedBits = ~stateBits & 0x3FF; 76 auto requested = control & 0x3FF; 77 if (control.checkBit(15)) { 78 if ((pressedBits & requested) == requested) { 79 interruptHandler.requestInterrupt(InterruptSource.KEYPAD); 80 } 81 } else if (pressedBits & requested) { 82 interruptHandler.requestInterrupt(InterruptSource.KEYPAD); 83 } 84 } 85 return 0; 86 } 87 }