summaryrefslogtreecommitdiff
path: root/apps/plugins/rockboy/lcdc.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/rockboy/lcdc.c')
-rw-r--r--apps/plugins/rockboy/lcdc.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/apps/plugins/rockboy/lcdc.c b/apps/plugins/rockboy/lcdc.c
new file mode 100644
index 0000000000..c82b828354
--- /dev/null
+++ b/apps/plugins/rockboy/lcdc.c
@@ -0,0 +1,180 @@
1
2
3#include "rockmacros.h"
4
5#include "defs.h"
6#include "hw.h"
7#include "cpu.h"
8#include "regs.h"
9#include "lcd.h"
10
11
12#define C (cpu.lcdc)
13
14
15/*
16 * stat_trigger updates the STAT interrupt line to reflect whether any
17 * of the conditions set to be tested (by bits 3-6 of R_STAT) are met.
18 * This function should be called whenever any of the following occur:
19 * 1) LY or LYC changes.
20 * 2) A state transition affects the low 2 bits of R_STAT (see below).
21 * 3) The program writes to the upper bits of R_STAT.
22 * stat_trigger also updates bit 2 of R_STAT to reflect whether LY=LYC.
23 */
24
25void stat_trigger(void)
26{
27 static const int condbits[4] = { 0x08, 0x30, 0x20, 0x00 };
28 int flag = 0;
29
30 if ((R_LY < 0x91) && (R_LY == R_LYC))
31 {
32 R_STAT |= 0x04;
33 if (R_STAT & 0x40) flag = IF_STAT;
34 }
35 else R_STAT &= ~0x04;
36
37 if (R_STAT & condbits[R_STAT&3]) flag = IF_STAT;
38
39 if (!(R_LCDC & 0x80)) flag = 0;
40
41 hw_interrupt(flag, IF_STAT);
42}
43
44void stat_write(byte b)
45{
46 R_STAT = (R_STAT & 0x07) | (b & 0x78);
47 if (!hw.cgb &&!(R_STAT & 2)) /* DMG STAT write bug => interrupt */
48 hw_interrupt(IF_STAT, IF_STAT);
49 stat_trigger();
50}
51
52
53/*
54 * stat_change is called when a transition results in a change to the
55 * LCD STAT condition (the low 2 bits of R_STAT). It raises or lowers
56 * the VBLANK interrupt line appropriately and calls stat_trigger to
57 * update the STAT interrupt line.
58 */
59
60static void stat_change(int stat)
61{
62 stat &= 3;
63 R_STAT = (R_STAT & 0x7C) | stat;
64
65 if (stat != 1) hw_interrupt(0, IF_VBLANK);
66 /* hw_interrupt((stat == 1) ? IF_VBLANK : 0, IF_VBLANK); */
67 stat_trigger();
68}
69
70
71void lcdc_change(byte b)
72{
73 byte old = R_LCDC;
74 R_LCDC = b;
75 if ((R_LCDC ^ old) & 0x80) /* lcd on/off change */
76 {
77 R_LY = 0;
78 stat_change(2);
79 C = 40;
80 lcd_begin();
81 }
82}
83
84
85void lcdc_trans(void)
86{
87 if (!(R_LCDC & 0x80))
88 {
89 while (C <= 0)
90 {
91 switch ((byte)(R_STAT & 3))
92 {
93 case 0:
94 case 1:
95 stat_change(2);
96 C += 40;
97 break;
98 case 2:
99 stat_change(3);
100 C += 86;
101 break;
102 case 3:
103 stat_change(0);
104 if (hw.hdma & 0x80)
105 hw_hdma();
106 else
107 C += 102;
108 break;
109 }
110 return;
111 }
112 }
113 while (C <= 0)
114 {
115 switch ((byte)(R_STAT & 3))
116 {
117 case 1:
118 if (!(hw.ilines & IF_VBLANK))
119 {
120 C += 218;
121 hw_interrupt(IF_VBLANK, IF_VBLANK);
122 break;
123 }
124 if (R_LY == 0)
125 {
126 lcd_begin();
127 stat_change(2);
128 C += 40;
129 break;
130 }
131 else if (R_LY < 152)
132 C += 228;
133 else if (R_LY == 152)
134 C += 28;
135 else
136 {
137 R_LY = -1;
138 C += 200;
139 }
140 R_LY++;
141 stat_trigger();
142 break;
143 case 2:
144 lcd_refreshline();
145 stat_change(3);
146 C += 86;
147 break;
148 case 3:
149 stat_change(0);
150 if (hw.hdma & 0x80)
151 hw_hdma();
152 /* FIXME -- how much of the hblank does hdma use?? */
153 /* else */
154 C += 102;
155 break;
156 case 0:
157 if (++R_LY >= 144)
158 {
159 if (cpu.halt)
160 {
161 hw_interrupt(IF_VBLANK, IF_VBLANK);
162 C += 228;
163 }
164 else C += 10;
165 stat_change(1);
166 break;
167 }
168 stat_change(2);
169 C += 40;
170 break;
171 }
172 }
173}
174
175
176
177
178
179
180