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