hw.c
1 2 3 4 #include "defs.h" 5 #include "cpu.h" 6 #include "hw.h" 7 #include "regs.h" 8 #include "lcd.h" 9 #include "mem.h" 10 11 12 struct hw hw; 13 14 15 16 /* 17 * hw_interrupt changes the virtual interrupt lines included in the 18 * specified mask to the values the corresponding bits in i take, and 19 * in doing so, raises the appropriate bit of R_IF for any interrupt 20 * lines that transition from low to high. 21 */ 22 23 void hw_interrupt(byte i, byte mask) 24 { 25 byte oldif = R_IF; 26 i &= 0x1F & mask; 27 R_IF |= i & (hw.ilines ^ i); 28 29 /* FIXME - is this correct? not sure the docs understand... */ 30 if ((R_IF & (R_IF ^ oldif) & R_IE) && cpu.ime) cpu.halt = 0; 31 /* if ((i & (hw.ilines ^ i) & R_IE) && cpu.ime) cpu.halt = 0; */ 32 /* if ((i & R_IE) && cpu.ime) cpu.halt = 0; */ 33 34 hw.ilines &= ~mask; 35 hw.ilines |= i; 36 } 37 38 39 /* 40 * hw_dma performs plain old memory-to-oam dma, the original dmg 41 * dma. Although on the hardware it takes a good deal of time, the cpu 42 * continues running during this mode of dma, so no special tricks to 43 * stall the cpu are necessary. 44 */ 45 46 void hw_dma(byte b) 47 { 48 int i; 49 addr a; 50 51 a = ((addr)b) << 8; 52 for (i = 0; i < XRES; i++, a++) 53 lcd.oam.mem[i] = readb(a); 54 } 55 56 57 58 void hw_hdma_cmd(byte c) 59 { 60 int cnt; 61 addr sa; 62 int da; 63 64 /* Begin or cancel HDMA */ 65 if ((hw.hdma|c) & 0x80) 66 { 67 hw.hdma = c; 68 R_HDMA5 = c & 0x7f; 69 return; 70 } 71 72 /* Perform GDMA */ 73 sa = ((addr)R_HDMA1 << 8) | (R_HDMA2&0xf0); 74 da = 0x8000 | ((int)(R_HDMA3&0x1f) << 8) | (R_HDMA4&0xf0); 75 cnt = ((int)c)+1; 76 /* FIXME - this should use cpu time! */ 77 /*cpu_timers(102 * cnt);*/ 78 cnt <<= 4; 79 while (cnt--) 80 writeb(da++, readb(sa++)); 81 R_HDMA1 = sa >> 8; 82 R_HDMA2 = sa & 0xF0; 83 R_HDMA3 = 0x1F & (da >> 8); 84 R_HDMA4 = da & 0xF0; 85 R_HDMA5 = 0xFF; 86 } 87 88 89 void hw_hdma() 90 { 91 int cnt; 92 addr sa; 93 int da; 94 95 sa = ((addr)R_HDMA1 << 8) | (R_HDMA2&0xf0); 96 da = 0x8000 | ((int)(R_HDMA3&0x1f) << 8) | (R_HDMA4&0xf0); 97 cnt = 16; 98 while (cnt--) 99 writeb(da++, readb(sa++)); 100 R_HDMA1 = sa >> 8; 101 R_HDMA2 = sa & 0xF0; 102 R_HDMA3 = 0x1F & (da >> 8); 103 R_HDMA4 = da & 0xF0; 104 R_HDMA5--; 105 hw.hdma--; 106 } 107 108 109 /* 110 * pad_refresh updates the P1 register from the pad states, generating 111 * the appropriate interrupts (by quickly raising and lowering the 112 * interrupt line) if a transition has been made. 113 */ 114 115 void pad_refresh() 116 { 117 byte oldp1; 118 oldp1 = R_P1; 119 R_P1 &= 0x30; 120 R_P1 |= 0xc0; 121 if (!(R_P1 & 0x10)) 122 R_P1 |= (hw.pad & 0x0F); 123 if (!(R_P1 & 0x20)) 124 R_P1 |= (hw.pad >> 4); 125 R_P1 ^= 0x0F; 126 if (oldp1 & ~R_P1 & 0x0F) 127 { 128 hw_interrupt(IF_PAD, IF_PAD); 129 hw_interrupt(0, IF_PAD); 130 } 131 } 132 133 134 /* 135 * These simple functions just update the state of a button on the 136 * pad. 137 */ 138 139 void pad_press(byte k) 140 { 141 if (hw.pad & k) 142 return; 143 hw.pad |= k; 144 pad_refresh(); 145 } 146 147 void pad_release(byte k) 148 { 149 if (!(hw.pad & k)) 150 return; 151 hw.pad &= ~k; 152 pad_refresh(); 153 } 154 155 void pad_set(byte k, int st) 156 { 157 st ? pad_press(k) : pad_release(k); 158 } 159 160 void hw_reset() 161 { 162 hw.ilines = hw.pad = 0; 163 164 memset(ram.hi, 0, sizeof ram.hi); 165 166 R_P1 = 0xFF; 167 R_LCDC = 0x91; 168 R_BGP = 0xFC; 169 R_OBP0 = 0xFF; 170 R_OBP1 = 0xFF; 171 R_SVBK = 0x01; 172 R_HDMA5 = 0xFF; 173 R_VBK = 0xFE; 174 } 175 176 177 178 179 180 181