Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/bsnes/snes/ppu/background/background.cpp
2 views
1
#ifdef PPU_CPP
2
3
#include "mode7.cpp"
4
5
//V = 0, H = 0
6
void PPU::Background::frame() {
7
}
8
9
//H = 0
10
void PPU::Background::scanline() {
11
}
12
13
//H = 60
14
void PPU::Background::begin() {
15
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
16
x = -7;
17
y = self.vcounter();
18
19
if(y == 1) {
20
mosaic.vcounter = regs.mosaic + 1;
21
mosaic.voffset = 1;
22
cache.hoffset = regs.hoffset;
23
cache.voffset = regs.voffset;
24
} else if(--mosaic.vcounter == 0) {
25
mosaic.vcounter = regs.mosaic + 1;
26
mosaic.voffset += regs.mosaic + 1;
27
cache.hoffset = regs.hoffset;
28
cache.voffset = regs.voffset;
29
}
30
31
tile_counter = (7 - (cache.hoffset & 7)) << hires;
32
for(unsigned n = 0; n < 8; n++) data[n] = 0;
33
34
mosaic.hcounter = regs.mosaic + 1;
35
mosaic.hoffset = 0;
36
37
if(regs.mode == Mode::Mode7) return begin_mode7();
38
if(regs.mosaic == 0) {
39
cache.hoffset = regs.hoffset;
40
cache.voffset = regs.voffset;
41
}
42
}
43
44
void PPU::Background::get_tile() {
45
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
46
47
unsigned color_depth = (regs.mode == Mode::BPP2 ? 0 : regs.mode == Mode::BPP4 ? 1 : 2);
48
unsigned palette_offset = (self.regs.bgmode == 0 ? id << 5 : 0);
49
unsigned palette_size = 2 << color_depth;
50
unsigned tile_mask = 0x0fff >> color_depth;
51
unsigned tiledata_index = regs.tiledata_addr >> (4 + color_depth);
52
53
unsigned tile_height = (regs.tile_size == TileSize::Size8x8 ? 3 : 4);
54
unsigned tile_width = (!hires ? tile_height : 4);
55
56
unsigned width = 256 << hires;
57
58
unsigned hmask = (tile_height == 3 ? width : width << 1);
59
unsigned vmask = hmask;
60
if(regs.screen_size & 1) hmask <<= 1;
61
if(regs.screen_size & 2) vmask <<= 1;
62
hmask--;
63
vmask--;
64
65
unsigned px = x << hires;
66
unsigned py = (regs.mosaic == 0 ? y : mosaic.voffset);
67
68
unsigned hscroll = cache.hoffset;
69
unsigned vscroll = cache.voffset;
70
if(hires) {
71
hscroll <<= 1;
72
if(self.regs.interlace) py = (py << 1) + self.field();
73
}
74
75
unsigned hoffset = hscroll + px;
76
unsigned voffset = vscroll + py;
77
78
if(self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6) {
79
uint16 offset_x = (x + (hscroll & 7));
80
81
if(offset_x >= 8) {
82
unsigned hval = self.bg3.get_tile((offset_x - 8) + (self.bg3.cache.hoffset & ~7), self.bg3.cache.voffset + 0);
83
unsigned vval = self.bg3.get_tile((offset_x - 8) + (self.bg3.cache.hoffset & ~7), self.bg3.cache.voffset + 8);
84
unsigned valid_mask = (id == ID::BG1 ? 0x2000 : 0x4000);
85
86
if(self.regs.bgmode == 4) {
87
if(hval & valid_mask) {
88
if((hval & 0x8000) == 0) {
89
hoffset = offset_x + (hval & ~7);
90
} else {
91
voffset = y + hval;
92
}
93
}
94
} else {
95
if(hval & valid_mask) hoffset = offset_x + (hval & ~7);
96
if(vval & valid_mask) voffset = y + vval;
97
}
98
}
99
}
100
101
hoffset &= hmask;
102
voffset &= vmask;
103
104
unsigned screen_x = (regs.screen_size & 1 ? 32 << 5 : 0);
105
unsigned screen_y = (regs.screen_size & 2 ? 32 << 5 : 0);
106
if(regs.screen_size == 3) screen_y <<= 1;
107
108
unsigned tx = hoffset >> tile_width;
109
unsigned ty = voffset >> tile_height;
110
111
uint16 offset = ((ty & 0x1f) << 5) + (tx & 0x1f);
112
if(tx & 0x20) offset += screen_x;
113
if(ty & 0x20) offset += screen_y;
114
115
uint16 addr = regs.screen_addr + (offset << 1);
116
tile = (ppu.vram[addr + 0] << 0) + (ppu.vram[addr + 1] << 8);
117
bool mirror_y = tile & 0x8000;
118
bool mirror_x = tile & 0x4000;
119
priority = (tile & 0x2000 ? regs.priority1 : regs.priority0);
120
palette_number = (tile >> 10) & 7;
121
palette_index = palette_offset + (palette_number << palette_size);
122
123
if(tile_width == 4 && (bool)(hoffset & 8) != mirror_x) tile += 1;
124
if(tile_height == 4 && (bool)(voffset & 8) != mirror_y) tile += 16;
125
uint16 character = ((tile & 0x03ff) + tiledata_index) & tile_mask;
126
127
if(mirror_y) voffset ^= 7;
128
offset = (character << (4 + color_depth)) + ((voffset & 7) << 1);
129
130
switch(regs.mode) {
131
case Mode::BPP8:
132
data[7] = ppu.vram[offset + 49];
133
data[6] = ppu.vram[offset + 48];
134
data[5] = ppu.vram[offset + 33];
135
data[4] = ppu.vram[offset + 32];
136
case Mode::BPP4:
137
data[3] = ppu.vram[offset + 17];
138
data[2] = ppu.vram[offset + 16];
139
case Mode::BPP2:
140
data[1] = ppu.vram[offset + 1];
141
data[0] = ppu.vram[offset + 0];
142
}
143
144
if(mirror_x) for(unsigned n = 0; n < 8; n++) {
145
//reverse data bits in data[n]: 01234567 -> 76543210
146
data[n] = ((data[n] >> 4) & 0x0f) | ((data[n] << 4) & 0xf0);
147
data[n] = ((data[n] >> 2) & 0x33) | ((data[n] << 2) & 0xcc);
148
data[n] = ((data[n] >> 1) & 0x55) | ((data[n] << 1) & 0xaa);
149
}
150
}
151
152
void PPU::Background::run(bool screen) {
153
if(self.vcounter() == 0) return;
154
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
155
156
if(screen == Screen::Sub) {
157
output.main.priority = 0;
158
output.sub.priority = 0;
159
if(hires == false) return;
160
}
161
162
if(regs.mode == Mode::Inactive) return;
163
if(regs.mode == Mode::Mode7) return run_mode7();
164
165
if(tile_counter-- == 0) {
166
tile_counter = 7;
167
get_tile();
168
}
169
170
uint8 palette = get_tile_color();
171
if(x == 0) mosaic.hcounter = 1;
172
if(x >= 0 && --mosaic.hcounter == 0) {
173
mosaic.hcounter = regs.mosaic + 1;
174
mosaic.priority = priority;
175
mosaic.palette = palette ? palette_index + palette : 0;
176
mosaic.tile = tile;
177
}
178
if(screen == Screen::Main) x++;
179
if(mosaic.palette == 0) return;
180
181
if(hires == false || screen == Screen::Main) if(regs.main_enable) output.main = mosaic;
182
if(hires == false || screen == Screen::Sub ) if(regs.sub_enable ) output.sub = mosaic;
183
}
184
185
unsigned PPU::Background::get_tile_color() {
186
unsigned color = 0;
187
188
switch(regs.mode) {
189
case Mode::BPP8:
190
color += (data[7] >> 0) & 0x80; data[7] <<= 1;
191
color += (data[6] >> 1) & 0x40; data[6] <<= 1;
192
color += (data[5] >> 2) & 0x20; data[5] <<= 1;
193
color += (data[4] >> 3) & 0x10; data[4] <<= 1;
194
case Mode::BPP4:
195
color += (data[3] >> 4) & 0x08; data[3] <<= 1;
196
color += (data[2] >> 5) & 0x04; data[2] <<= 1;
197
case Mode::BPP2:
198
color += (data[1] >> 6) & 0x02; data[1] <<= 1;
199
color += (data[0] >> 7) & 0x01; data[0] <<= 1;
200
}
201
202
return color;
203
}
204
205
void PPU::Background::reset() {
206
regs.tiledata_addr = (random(0x0000) & 0x07) << 13;
207
regs.screen_addr = (random(0x0000) & 0x7c) << 9;
208
regs.screen_size = random(0);
209
regs.mosaic = random(0);
210
regs.tile_size = random(0);
211
regs.mode = 0;
212
regs.priority0 = 0;
213
regs.priority1 = 0;
214
regs.main_enable = random(0);
215
regs.sub_enable = random(0);
216
regs.hoffset = random(0x0000);
217
regs.voffset = random(0x0000);
218
219
cache.hoffset = 0;
220
cache.voffset = 0;
221
222
output.main.palette = 0;
223
output.main.priority = 0;
224
output.sub.palette = 0;
225
output.sub.priority = 0;
226
227
mosaic.priority = 0;
228
mosaic.palette = 0;
229
mosaic.tile = 0;
230
231
mosaic.vcounter = 0;
232
mosaic.voffset = 0;
233
mosaic.hcounter = 0;
234
mosaic.hoffset = 0;
235
236
x = 0;
237
y = 0;
238
239
tile_counter = 0;
240
tile = 0;
241
priority = 0;
242
palette_number = 0;
243
palette_index = 0;
244
for(unsigned n = 0; n < 8; n++) data[n] = 0;
245
}
246
247
unsigned PPU::Background::get_tile(unsigned x, unsigned y) {
248
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
249
unsigned tile_height = (regs.tile_size == TileSize::Size8x8 ? 3 : 4);
250
unsigned tile_width = (!hires ? tile_height : 4);
251
unsigned width = (!hires ? 256 : 512);
252
unsigned mask_x = (tile_height == 3 ? width : width << 1);
253
unsigned mask_y = mask_x;
254
if(regs.screen_size & 1) mask_x <<= 1;
255
if(regs.screen_size & 2) mask_y <<= 1;
256
mask_x--;
257
mask_y--;
258
259
unsigned screen_x = (regs.screen_size & 1 ? 32 << 5 : 0);
260
unsigned screen_y = (regs.screen_size & 2 ? 32 << 5 : 0);
261
if(regs.screen_size == 3) screen_y <<= 1;
262
263
x = (x & mask_x) >> tile_width;
264
y = (y & mask_y) >> tile_height;
265
266
uint16 offset = ((y & 0x1f) << 5) + (x & 0x1f);
267
if(x & 0x20) offset += screen_x;
268
if(y & 0x20) offset += screen_y;
269
270
uint16 addr = regs.screen_addr + (offset << 1);
271
return (ppu.vram[addr + 0] << 0) + (ppu.vram[addr + 1] << 8);
272
}
273
274
PPU::Background::Background(PPU &self, unsigned id) : self(self), id(id) {
275
}
276
277
#endif
278
279