forked from badman12345/osmose-rpi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
VDP_GG.cpp
254 lines (223 loc) · 7.44 KB
/
VDP_GG.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/*****************************************************************************
*
* File: VDP_GG.cpp
*
* Project: Osmose emulator.
*
* Description: This class will handle GAMEGEAR's VDP (Video Display Processor)operation.
*
* Author: Vedder Bruno
* Date: 25/10/2006, 19h15
*
* URL: http://bcz.emu-france.com/
*****************************************************************************/
#include "VDP_GG.h"
static unsigned color_latch = 0;
/*----------------------------------------------------------------------*/
/* VDP_GG Constructor. */
/*----------------------------------------------------------------------*/
VDP_GG::VDP_GG(Z80 *c, bool ntsc) : VDP( c, ntsc )
{
}
/*----------------------------------------------------------------------*/
/* This method handles write operation on the GAMEGEAR VDP data port. */
/*----------------------------------------------------------------------*/
void VDP_GG::writeDataPort(unsigned char data) /* Port 0xBE written */
{
cmd_flag = false;
rd_data_port_buffer = data; // CMD docs says that write, load buffer with it's value.
// destination is VRAM or CRAM ?
if (cmd_type == 3)
{
if (!(addr & 0x1))
{
color_latch = data;
}
else
{
//CRAM[addr & 0x3F] = data; // data not anded with 1f. It's done with rgb rate.
unsigned short col = ((data & 0xF) <<8) | color_latch;
unsigned short *cram_w = (unsigned short*) &CRAM[addr & 0x3e];
*cram_w = col;
colors[(addr>>1) & 0x1f] = colorGG12BitsToColor16Bits( col );
}
addr++;
addr &=0x3FFF;
}
else // Destination is VRAM
{
VRAM[addr] = data;
#ifdef VDP_VERBOSE
cout << "VRAM written: at 0x" << hex << setw(4) << setfill('0')<< addr << " with value "<< setw(2) << setfill('0') <<(int)data <<endl;
#endif
addr++;
addr &=0x3FFF;
}
}
/*--------------------------------------------------------------*/
/* This method draws a scanline. */
/* */
/* Drawing is done in two pass: */
/* - Render tile background */
/* (sprite are rendered, then) */
/* - Render tile that cover sprites */
/*--------------------------------------------------------------*/
void VDP_GG::traceBackGroundLine(SDL_Surface *s)
{
unsigned int c,pos;
unsigned short *dst;
unsigned short *scr;
unsigned short currentTile;
unsigned char i, o, x, y, col_index, attrib;
int current_line;
unsigned int p;
// scr ptr in our SDL_Surface points line to be drawn.
scr = (unsigned short*) s->pixels + (256 * line);
/* Fill the undrawn lines with 00.*/
if ((line<24) || (line>167))
{
memset(scr, 0x0, 0x200);
return;
}
dst = line_buffer;
/* Clear our tileMask. */
memset(tile_mask,0x00, 0x100);
/*
Note that x is never tested for >255 since it automaticaly wraps
due to it's unsigned char declaration.
*/
/* Now, for 32 tiles... */
for (o=0; o<32;o++)
{
/* Draw a blank line directly in screen if display is disabled. */
if (!(REG1 & BIT6))
{
memset(scr,0x00, 0x200); // 0x200 means 256 16bits pixels.
return;
}
/* x = X scroll register, y = Y scroll register. */
y = REG9;
x = REG8;
/* Top 2 rows of screen not affected by horizontal scrolling. */
if ((REG0 & BIT6) && (line<=15))
{
x = 0;
}
x += o *8;
/* current_line = current line + scroll register modulated to stay in screen. 192 could be OK. */
if ((o >= 24) && (REG0 & BIT7))
{
/* Disable vertical scrolling for columns 24-31 */
current_line = ((line) % 224);
}
else
{
current_line = ((line+y) % 224);
}
/*
Now get VRAM index of the Tile/attrib in VDP memory.
8x8 Tile at Coord x, y = (x*64) + (y /8)
x * 64 because a line is 32 tiles, with 2 bytes for tile index and attribute.
y /8 because a tile is made of 8 lines.
*/
pos = ((current_line>>3)<<6) + o * 2;
/* get it's tile Index. */
currentTile = VRAM[ map_addr + pos++];
/* get it's attribute. */
attrib = VRAM[ map_addr + pos++];
if(attrib & BIT0)
{
currentTile |=0x100; // 9th tile index bit.
}
// line in tile converted to VRAM ind
if (attrib & BIT2)
{
// Verticaly flipped tile.
c = (7 - ((current_line & 7) )<<2) + (currentTile<<5);
}
else
{
c = ((current_line & 7)<<2) + (currentTile<<5);
}
// Four bytes are read into one 32bits variable. This avoid 3 memory access.
// Bits plan are like this in the variable (intel architecture):
// P3P2P1P0 which is inverse order or ram content. This is due to intel
// endianness
unsigned int *cst = (unsigned int *) &VRAM[c];
p = *cst;
c += 4;
// Draw 8 horizontals pixels.
switch ((attrib>>1) & 3)
{
case 0: // Tile not flipped
for ( i = 0; i<8; i++)
{
col_index = (p >>7)&1 | ((p >> 15)<<1)&2 | ((p >> 23)<<2)&4 | ((p >> 31)<<3);
if(attrib & BIT3) col_index|=0x10; // Then use sprite palete
dst[x] = colors[col_index];
if ((attrib & BIT4) && (col_index != 0x10) && (col_index !=0x0))
{
tile_mask[x] = 1;
}
x++;
p<<=1;
}
break;
case 1: // Tile flipped on x
for ( i = 0; i<8; i++)
{
col_index = (p&1) | ((p>>8) & 1)<<1 | ((p>>16) & 1 )<<2 | ((p >>24) &1)<<3;
if(attrib & BIT3) col_index|=0x10; // Then use sprite palete
dst[x] = colors[col_index];
if ((attrib & BIT4) && (col_index != 0x10) && (col_index !=0x0))
{
tile_mask[x] = 1;
}
x++;
p>>=1;
}
break;
case 2: // Tile flipped on y
for (int i=0; i<8;i++)
{
col_index = ((p>>7) &1)| ((p >> 15)&1)<<1 | ((p >> 23)&1)<<2 | ((p >> 31)&1)<<3;
if(attrib & BIT3) col_index|=0x10; // Then use sprite palete
dst[x] = colors[col_index];
if ((attrib & BIT4) && (col_index != 0x10) && (col_index !=0x0))
{
tile_mask[x] = 1;
}
x++;
p<<=1;
}
break;
case 3: // Tile flipped on x and y
for (int i=0; i<8;i++)
{
col_index = (p & 1) | ((p>>8) & 1)<<1 | ((p>>16) & 1)<<2 | ((p>>24) & 1)<<3;
if(attrib & BIT3) col_index|=0x10; // Then use sprite palete
dst[x] = colors[col_index];
if ((attrib & BIT4) && (col_index != 0x10) && (col_index !=0x0))
{
tile_mask[x] = 1;
}
x++;
p>>=1;
}
break;
} // switch attrib flip x/y
}
#ifdef DISPLAY_SPRITES
displaySpritesLine();
#endif
if (REG0 & BIT5) // Do not display (clear) leftmost column of the screen
{
unsigned short c = colors[(REG7 & 0xF)+16];
for (int u=0; u < 8; u++)
{
dst[u] = c;
}
}
// Copy Partial buffer_line in screen line:
memcpy(scr+48,dst+48, 320);
}