rockbox/apps/plugins/rockboy/hw.c
Tom Ross 2882b26a99 Major Rockboy update.
1) Adapt Rockboy to smaller screens (H10, X5, and iPod Nano).
2) Add the ability to use a preset palette on color targets. Choose 'Set Palette' from the main menu.
3) Clean up the code to remove any unused code and variables.
4) Changed tabs to spaces.
5) Disable reading and writing sound when sound is disabled.
6) Disbable writing to the RTC since it is not implemented yet.
7) Minor optimizations from WAC gnuboy CE and iBoy.
8) Massive clean up of code to make it appear consistent.
9) Change all C++ style comments to C style.
10) Completely reorganize dynarec. Add fixmes to all unimplemented opcodes. Add debug writes for all opcodes. Attempt to implement a few opcodes myself.
11) Silence some warnings when built using dynarec.
12) Minor reshuffling of IRAM, may or not offer a speed increase.
13) Include fixes found in the short-lived gnuboy CVS.

All in all, there's about a 10% improvement on my test roms when sound is disabled and slight improvement with sound. Especially noticable when there are few sprites on screen and less action is occurring. See FS #6567.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12216 a1c6a512-1295-4272-9138-f99709370657
2007-02-06 21:41:08 +00:00

177 lines
3.5 KiB
C

#include "rockmacros.h"
#include "defs.h"
#include "cpu-gb.h"
#include "hw.h"
#include "regs.h"
#include "lcd-gb.h"
#include "mem.h"
#include "fastmem.h"
struct hw hw IBSS_ATTR;
/*
* 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(void)
{
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++));
cpu_timers(16);
R_HDMA1 = sa >> 8;
R_HDMA2 = sa & 0xF0;
R_HDMA3 = 0x1F & (da >> 8);
R_HDMA4 = da & 0xF0;
R_HDMA5--;
hw.hdma--;
}
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;
if ((R_STAT&0x03) == 0x00) hw_hdma();
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);*/
cpu_timers((460>>cpu.speed)+cnt*16); /*dalias*/
/*cpu_timers(228 + (16*cnt));*/ /* this should be right according to no$ */
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;
}
/*
* 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;
}