summaryrefslogtreecommitdiff
path: root/apps/plugins/rockboy/hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/rockboy/hw.c')
-rw-r--r--apps/plugins/rockboy/hw.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/apps/plugins/rockboy/hw.c b/apps/plugins/rockboy/hw.c
new file mode 100644
index 0000000..c287e24
--- /dev/null
+++ b/apps/plugins/rockboy/hw.c
@@ -0,0 +1,183 @@
+
+
+
+#include "rockmacros.h"
+#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(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++));
+ 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;
+}
+
+
+
+
+
+
+