Commit | Line | Data |
---|---|---|
1ab64c54 GI |
1 | /* |
2 | * (C) GraÅžvydas "notaz" Ignotas, 2011 | |
3 | * | |
4 | * This work is licensed under the terms of any of these licenses | |
5 | * (at your option): | |
6 | * - GNU GPL, version 2 or later. | |
7 | * - GNU LGPL, version 2.1 or later. | |
8 | * See the COPYING file in the top-level directory. | |
9 | */ | |
10 | ||
11 | #include <stdint.h> | |
12 | #include <string.h> | |
13 | ||
14 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | |
15 | ||
16 | static struct { | |
17 | uint16_t vram[1024 * 512]; | |
18 | uint16_t guard[1024 * 512]; // overdraw guard | |
19 | uint32_t regs[16]; | |
20 | union { | |
21 | uint32_t reg; | |
22 | struct { | |
23 | uint32_t tx:4; // 0 texture page | |
24 | uint32_t ty:1; | |
25 | uint32_t abr:2; | |
26 | uint32_t tp:2; // 7 t.p. mode (4,8,15bpp) | |
27 | uint32_t dtd:1; // 9 dither | |
28 | uint32_t dfe:1; | |
29 | uint32_t md:1; // 11 set mask bit when drawing | |
30 | uint32_t me:1; // 12 no draw on mask | |
31 | uint32_t unkn:3; | |
32 | uint32_t width1:1;// 16 | |
33 | uint32_t width0:2; | |
34 | uint32_t height:1; | |
35 | uint32_t video:1; // 20 NTSC,PAL | |
36 | uint32_t rgb24:1; | |
37 | uint32_t inter:1; // 22 interlace on | |
38 | uint32_t den:1; // 23 display not enabled | |
39 | uint32_t unkn2:2; | |
40 | uint32_t busy:1; // 26 !busy drawing | |
41 | uint32_t img:1; // 27 ready to DMA | |
42 | uint32_t com:1; // 28 ready for commands | |
43 | uint32_t dma:2; // 29 off, ?, to vram, from vram | |
44 | uint32_t lcf:1; // 21 odd frame/blanking? | |
45 | }; | |
46 | } status; | |
47 | struct { | |
48 | int x, y, w, h; | |
49 | int y1, y2; | |
50 | } screen; | |
51 | uint32_t blanking; | |
52 | } gpu; | |
53 | ||
54 | long GPUinit(void) | |
55 | { | |
56 | return 0; | |
57 | } | |
58 | ||
59 | long GPUshutdown(void) | |
60 | { | |
61 | return 0; | |
62 | } | |
63 | ||
64 | uint32_t GPUreadStatus(void) | |
65 | { | |
66 | return gpu.status.reg | (gpu.blanking << 31); | |
67 | } | |
68 | ||
69 | void GPUwriteStatus(uint32_t data) | |
70 | { | |
71 | static const short hres[8] = { 256, 368, 320, 384, 512, 512, 640, 640 }; | |
72 | static const short vres[4] = { 240, 480, 256, 480 }; | |
73 | uint32_t cmd = data >> 24; | |
74 | ||
75 | switch (data >> 24) { | |
76 | case 0x00: | |
77 | break; | |
78 | case 0x03: | |
79 | gpu.status.den = data & 1; | |
80 | break; | |
81 | case 0x04: | |
82 | gpu.status.dma = data & 3; | |
83 | break; | |
84 | case 0x05: | |
85 | gpu.screen.x = data & 0x3ff; | |
86 | gpu.screen.y = (data >> 10) & 0x3ff; | |
87 | break; | |
88 | case 0x07: | |
89 | gpu.screen.y1 = data & 0x3ff; | |
90 | gpu.screen.y2 = (data >> 10) & 0x3ff; | |
91 | break; | |
92 | case 0x08: | |
93 | gpu.status.reg = (gpu.status.reg & ~0x7f0000) | ((data & 0x3F) << 17) | ((data & 0x40) << 10); | |
94 | gpu.screen.w = hres[(gpu.status.reg >> 16) & 7]; | |
95 | gpu.screen.h = vres[(gpu.status.reg >> 19) & 3]; | |
96 | break; | |
97 | } | |
98 | ||
99 | if (cmd < ARRAY_SIZE(gpu.regs)) | |
100 | gpu.regs[cmd] = data; | |
101 | } | |
102 | ||
103 | void GPUreadDataMem(uint32_t *mem, int count) | |
104 | { | |
105 | } | |
106 | ||
107 | uint32_t GPUreadData(void) | |
108 | { | |
109 | return 0; | |
110 | } | |
111 | ||
112 | void GPUwriteDataMem(uint32_t *mem, int count) | |
113 | { | |
114 | } | |
115 | ||
116 | void GPUwriteData(uint32_t gdata) | |
117 | { | |
118 | } | |
119 | ||
120 | long GPUdmaChain(uint32_t *base, uint32_t addr) | |
121 | { | |
122 | return 0; | |
123 | } | |
124 | ||
125 | typedef struct GPUFREEZETAG | |
126 | { | |
127 | uint32_t ulFreezeVersion; // should be always 1 for now (set by main emu) | |
128 | uint32_t ulStatus; // current gpu status | |
129 | uint32_t ulControl[256]; // latest control register values | |
130 | unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN) | |
131 | } GPUFreeze_t; | |
132 | ||
133 | long GPUfreeze(uint32_t type, GPUFreeze_t *freeze) | |
134 | { | |
135 | switch (type) { | |
136 | case 1: // save | |
137 | memcpy(freeze->psxVRam, gpu.vram, sizeof(gpu.vram)); | |
138 | memcpy(freeze->ulControl, gpu.regs, sizeof(gpu.regs)); | |
139 | freeze->ulStatus = gpu.status.reg; | |
140 | freeze->ulControl[255] = gpu.blanking; // abuse free space | |
141 | break; | |
142 | case 0: // load | |
143 | memcpy(gpu.vram, freeze->psxVRam, sizeof(gpu.vram)); | |
144 | memcpy(gpu.regs, freeze->ulControl, sizeof(gpu.regs)); | |
145 | gpu.status.reg = freeze->ulStatus; | |
146 | gpu.blanking = freeze->ulControl[255]; | |
147 | GPUwriteStatus((5 << 24) | gpu.regs[5]); | |
148 | GPUwriteStatus((7 << 24) | gpu.regs[7]); | |
149 | GPUwriteStatus((8 << 24) | gpu.regs[8]); | |
150 | break; | |
151 | } | |
152 | ||
153 | return 1; | |
154 | } | |
155 | ||
156 | void GPUvBlank(int val) | |
157 | { | |
158 | gpu.blanking = !!val; | |
159 | } | |
160 | ||
161 | // rearmed specific | |
162 | ||
163 | #include "../../frontend/plugin_lib.h" | |
164 | #include "../../frontend/arm_utils.h" | |
165 | ||
166 | static const struct rearmed_cbs *cbs; | |
167 | static void *screen_buf; | |
168 | ||
169 | static void blit(void) | |
170 | { | |
171 | static uint32_t old_status, old_h; | |
172 | int x = gpu.screen.x & ~3; // alignment needed by blitter | |
173 | int y = gpu.screen.y; | |
174 | int w = gpu.screen.w; | |
175 | int h; | |
176 | uint16_t *srcs; | |
177 | uint8_t *dest; | |
178 | ||
179 | srcs = &gpu.vram[y * 1024 + x]; | |
180 | ||
181 | h = gpu.screen.y2 - gpu.screen.y1; | |
182 | ||
183 | if (h <= 0) | |
184 | return; | |
185 | ||
186 | if ((gpu.status.reg ^ old_status) & ((7<<16)|(1<<21)) || h != old_h) // width|rgb24 change? | |
187 | { | |
188 | old_status = gpu.status.reg; | |
189 | old_h = h; | |
190 | screen_buf = cbs->pl_fbdev_set_mode(w, h, gpu.status.rgb24 ? 24 : 16); | |
191 | } | |
192 | dest = screen_buf; | |
193 | ||
194 | if (gpu.status.rgb24) | |
195 | { | |
196 | #ifndef MAEMO | |
197 | for (; h-- > 0; dest += w * 3, srcs += 1024) | |
198 | { | |
199 | bgr888_to_rgb888(dest, srcs, w * 3); | |
200 | } | |
201 | #else | |
202 | for (; h-- > 0; dest += w * 2, srcs += 1024) | |
203 | { | |
204 | bgr888_to_rgb565(dest, srcs, w * 3); | |
205 | } | |
206 | #endif | |
207 | } | |
208 | else | |
209 | { | |
210 | for (; h-- > 0; dest += w * 2, srcs += 1024) | |
211 | { | |
212 | bgr555_to_rgb565(dest, srcs, w * 2); | |
213 | } | |
214 | } | |
215 | ||
216 | screen_buf = cbs->pl_fbdev_flip(); | |
217 | } | |
218 | ||
219 | void GPUupdateLace(void) | |
220 | { | |
221 | blit(); | |
222 | } | |
223 | ||
224 | long GPUopen(void) | |
225 | { | |
226 | cbs->pl_fbdev_open(); | |
227 | screen_buf = cbs->pl_fbdev_flip(); | |
228 | return 0; | |
229 | } | |
230 | ||
231 | long GPUclose(void) | |
232 | { | |
233 | cbs->pl_fbdev_close(); | |
234 | return 0; | |
235 | } | |
236 | ||
237 | void GPUrearmedCallbacks(const struct rearmed_cbs *cbs_) | |
238 | { | |
239 | cbs = cbs_; | |
240 | } | |
241 | ||
242 | // vim:shiftwidth=2:expandtab |