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