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 }