diff options
Diffstat (limited to 'apps/plugins/rockboy/lcdc.c')
-rw-r--r-- | apps/plugins/rockboy/lcdc.c | 180 |
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 | |||
25 | void 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 | |||
44 | void 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 | |||
60 | static 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 | |||
71 | void 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 | |||
85 | void 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 | |||