7 #include "lib/string.h"
10 static int lcd_cycles;
11 static int lcd_line, prev_line;
12 static int lcd_ly_compare;
17 static int vblank_int;
18 static int hblank_int;
21 static int irq_level, new_level;
24 static int lcd_enabled;
25 static int window_tilemap_select;
26 static int window_enabled;
27 static int tilemap_select;
28 static int bg_tiledata_select;
29 static int sprite_size;
30 static int sprites_enabled;
31 static int bg_enabled;
32 static int scroll_x, scroll_y;
33 static int window_x, window_y;
35 static int bgpalette[] = {0, 3, 3, 3};
36 static int sprpalette1[] = {0, 1, 2, 3};
37 static int sprpalette2[] = {0, 1, 2, 3};
38 static unsigned long colours[4] = {0xF4FFF4, 0xC0D0C0, 0x80A080, 0x001000};
41 int y, x, tile, flags;
58 void lcd_write_bg_palette(
unsigned char n)
60 bgpalette[0] = (n>>0)&3;
61 bgpalette[1] = (n>>2)&3;
62 bgpalette[2] = (n>>4)&3;
63 bgpalette[3] = (n>>6)&3;
66 void lcd_write_spr_palette1(
unsigned char n)
69 sprpalette1[1] = (n>>2)&3;
70 sprpalette1[2] = (n>>4)&3;
71 sprpalette1[3] = (n>>6)&3;
74 void lcd_write_spr_palette2(
unsigned char n)
77 sprpalette2[1] = (n>>2)&3;
78 sprpalette2[2] = (n>>4)&3;
79 sprpalette2[3] = (n>>6)&3;
82 void lcd_write_scroll_x(
unsigned char n)
87 void lcd_write_scroll_y(
unsigned char n)
92 int lcd_get_line(
void)
97 if(lcd_line == 153 && (leftover % 456) >= 4)
104 unsigned char lcd_get_stat(
void)
106 unsigned char coincidence = (lcd_line == lcd_ly_compare) << 2;
107 return 0x80 | ly_int | oam_int | vblank_int | hblank_int | coincidence | lcd_mode;
110 void lcd_write_stat(
unsigned char c)
118 static unsigned int *b;
120 void lcd_write_control(
unsigned char c)
123 if(!lcd_enabled && (c & 0x80))
126 bg_enabled = !!(c & 0x01);
127 sprites_enabled = !!(c & 0x02);
128 sprite_size = !!(c & 0x04);
129 tilemap_select = !!(c & 0x08);
130 bg_tiledata_select = !!(c & 0x10);
131 window_enabled = !!(c & 0x20);
132 window_tilemap_select = !!(c & 0x40);
133 lcd_enabled = !!(c & 0x80);
136 unsigned char lcd_get_ly_compare(
void)
138 return lcd_ly_compare;
141 void lcd_set_ly_compare(
unsigned char c)
146 void lcd_set_window_y(
unsigned char n) {
150 void lcd_set_window_x(
unsigned char n) {
154 static void POKE(
unsigned int x,
int y,
int c)
156 b[(y*4+0)*640 + x*4+0] = c;
157 b[(y*4+0)*640 + x*4+1] = c;
158 b[(y*4+0)*640 + x*4+2] = c;
159 b[(y*4+0)*640 + x*4+3] = c;
161 b[(y*4+1)*640 + x*4+0] = c;
162 b[(y*4+1)*640 + x*4+1] = c;
163 b[(y*4+1)*640 + x*4+2] = c;
164 b[(y*4+1)*640 + x*4+3] = c;
166 b[(y*4+2)*640 + x*4+0] = c;
167 b[(y*4+2)*640 + x*4+1] = c;
168 b[(y*4+2)*640 + x*4+2] = c;
169 b[(y*4+2)*640 + x*4+3] = c;
171 b[(y*4+3)*640 + x*4+0] = c;
172 b[(y*4+3)*640 + x*4+1] = c;
173 b[(y*4+3)*640 + x*4+2] = c;
174 b[(y*4+3)*640 + x*4+3] = c;
186 static void sort_sprites(
struct sprite *s,
int n)
193 for(i = 0; i < n-1; i++)
195 if(s[i].x > s[i+1].x)
197 swap(&s[i], &s[i+1]);
205 static int sprites_update(
int line,
struct sprite *spr)
209 for(i = 0; i < 40; i++)
213 y = mem_get_raw(0xFE00 + (i*4) + 0) - 16;
215 if(line < y || line >= y + 8 + (sprite_size*8))
219 spr[c].x = mem_get_raw(0xFE00 + (i*4) + 1) - 8;
220 spr[c].tile = mem_get_raw(0xFE00 + (i*4) + 2);
221 spr[c].flags = mem_get_raw(0xFE00 + (i*4) + 3);
229 sort_sprites(spr, c);
241 static void sprite_fetch(
int line,
struct oam_cache *o)
244 int i, x, sprite_count;
247 sprite_count = sprites_update(line, spr);
252 for(i = 0; i < sprite_count; i++)
255 unsigned short tile_addr;
256 unsigned char b1, b2, mask;
262 if(spr[i].flags & VFLIP)
263 sprite_line = (sprite_size ? 15 : 7) - (line - spr[i].y);
265 sprite_line = line - spr[i].y;
268 tile_addr = 0x8000 + (spr[i].tile & 0xFE) * 16 + sprite_line * 2;
270 tile_addr = 0x8000 + spr[i].tile * 16 + sprite_line * 2;
272 b1 = mem_get_raw(tile_addr);
273 b2 = mem_get_raw(tile_addr + 1);
275 for(x = spr[i].x; x < spr[i].x + 8; x++)
289 mask = spr[i].flags & HFLIP ? 128>>(7-relx) : 128>>relx;
290 new_col = (!!(b2&mask))<<1 | !!(b1&mask);
297 o[x].colour = new_col;
298 o[x].prio = spr[i].flags & PRIO;
299 o[x].pal = spr[i].flags & PNUM;
305 static void lcd_do_line(
int line,
int cycle)
308 static int line_fill, fetch_delay, window_lines, window_used_line, window_used_frame;
309 static unsigned char scx_low_latch;
321 window_used_frame = 0;
325 if(lcd_mode != 2 && cycle < 80)
330 if(lcd_mode == 2 && cycle >= 80)
332 scx_low_latch = scroll_x & 7;
333 sprite_fetch(line, o);
343 int colour = 0, bgcol;
344 unsigned int map_select, map_offset, tile_num, tile_addr, xm, ym;
345 unsigned char b1, b2, mask;
347 if(line >= window_y && window_enabled && line - window_y < 144 && (window_x - 7) <= line_fill)
349 if(!window_used_frame && line == window_y)
350 window_used_frame = 1;
352 if(!window_used_frame)
354 xm = line_fill - (window_x-7);
356 map_select = window_tilemap_select;
357 window_used_line = 1;
368 xm = (line_fill + (scroll_x & 0xF8) + scx_low_latch)%256;
369 ym = (line + scroll_y)%256;
370 map_select = tilemap_select;
373 map_offset = (ym/8)*32 + xm/8;
375 tile_num = mem_get_raw(0x9800 + map_select*0x400 + map_offset);
376 if(bg_tiledata_select)
377 tile_addr = 0x8000 + tile_num*16;
379 tile_addr = 0x9000 + ((
signed char)tile_num)*16;
381 b1 = mem_get_raw(tile_addr+(ym%8)*2);
382 b2 = mem_get_raw(tile_addr+(ym%8)*2+1);
386 bgcol = (!!(b2&mask)<<1) | !!(b1&mask);
391 if(sprites_enabled && oc->colour && ((oc->prio && !bgcol) || (!oc->prio)))
393 int *pal = oc->pal ? sprpalette2 : sprpalette1;
394 colour = colours[pal[(int)oc->colour]];
398 colour = colours[bgpalette[bgcol]];
401 POKE(line_fill, line, colour);
403 if(line_fill++ == 159)
409 window_used_line = 0;
415 static void lcd_interrupt(
enum LCD_INT src)
419 if(!!irq_level != !!new_level)
420 interrupt(INTR_LCDSTAT);
426 leftover = lcd_cycles % (456 * 154);
429 lcd_line = leftover / 456;
435 if(lcd_line == lcd_ly_compare || (lcd_line == 153 && lcd_ly_compare == 0 && (leftover % 456) >= 4))
436 lcd_interrupt(LCD_LY);
438 if(oam_int && lcd_mode == 2)
439 lcd_interrupt(LCD_OAM);
440 if(vblank_int && lcd_line >= 144)
441 lcd_interrupt(LCD_VBLANK);
442 if(hblank_int && lcd_mode == 0)
443 lcd_interrupt(LCD_HBLANK);
445 lcd_do_line(lcd_line, leftover % 456);
448 if(lcd_line == 144 && prev_line == 143)
456 interrupt(INTR_VBLANK);
460 prev_line = lcd_line;
464 irq_level = new_level;
478 b = sdl_get_framebuffer();
481 lcd_write_control(91);
void * memset(void *ptr, char value, size_t num)
Заполнение массива указанными символами