A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1#include "rockmacros.h"
2
3#include "defs.h"
4#include "hw.h"
5#include "cpu-gb.h"
6#include "regs.h"
7#include "lcd-gb.h"
8#include "fb.h"
9#include "lcdc.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, 0x10, 0x20, 0x00 };
28 int flag = 0;
29
30 if (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/*
45 * stat_change is called when a transition results in a change to the
46 * LCD STAT condition (the low 2 bits of R_STAT). It raises or lowers
47 * the VBLANK interrupt line appropriately and calls stat_trigger to
48 * update the STAT interrupt line.
49 */
50
51static void stat_change(unsigned int stat)
52{
53 R_STAT = (R_STAT & 0x7C) | stat;
54
55 if (stat != 1) hw_interrupt(0, IF_VBLANK);
56 /* hw_interrupt((stat == 1) ? IF_VBLANK : 0, IF_VBLANK); */
57 stat_trigger();
58}
59
60
61void lcdc_change(byte b)
62{
63 byte old = R_LCDC;
64 R_LCDC = b;
65 if ((R_LCDC ^ old) & 0x80) /* lcd on/off change */
66 {
67 R_LY = 0;
68 stat_change(2);
69 C = 40;
70 lcd_begin();
71 }
72}
73
74
75void lcdc_trans(void)
76{
77 if (!(R_LCDC & 0x80))
78 {
79 while (C <= 0)
80 {
81 switch ((byte)(R_STAT & 3))
82 {
83 case 0:
84 case 1:
85 stat_change(2);
86 C += 40;
87 break;
88 case 2:
89 stat_change(3);
90 C += 86;
91 break;
92 case 3:
93 stat_change(0);
94 if (hw.hdma & 0x80)
95 hw_hdma();
96 else
97 C += 102;
98 break;
99 }
100 return;
101 }
102 }
103 while (C <= 0)
104 {
105 switch ((byte)(R_STAT & 3))
106 {
107 case 1:
108 if (!(hw.ilines & IF_VBLANK))
109 {
110 C += 218;
111 hw_interrupt(IF_VBLANK, IF_VBLANK);
112 break;
113 }
114 if (R_LY == 0)
115 {
116 lcd_begin();
117 stat_change(2);
118 C += 40;
119 break;
120 }
121 else if (R_LY < 152)
122 C += 228;
123 else if (R_LY == 152)
124 C += 28;
125 else
126 {
127 R_LY = -1;
128 C += 200;
129 }
130 R_LY++;
131 stat_trigger();
132 break;
133 case 2:
134 if (fb.enabled)
135 lcd_refreshline();
136 stat_change(3);
137 C += 86;
138 break;
139 case 3:
140 stat_change(0);
141 if (hw.hdma & 0x80)
142 hw_hdma();
143 /* FIXME -- how much of the hblank does hdma use?? */
144 /* else */
145 C += 102;
146 break;
147 case 0:
148 if (++R_LY >= 144)
149 {
150 if (cpu.halt)
151 {
152 hw_interrupt(IF_VBLANK, IF_VBLANK);
153 C += 228;
154 }
155 else C += 10;
156 stat_change(1);
157 break;
158 }
159 stat_change(2);
160 C += 40;
161 break;
162 }
163 }
164}
165
166
167
168
169
170
171