diff --git a/source/render.c b/source/render.c index d8b0a27..89d15f4 100644 --- a/source/render.c +++ b/source/render.c @@ -40,19 +40,38 @@ typedef struct uint8 right; uint8 enable; }clip_t; - + /* Function prototypes */ -static void render_obj(uint32 line, uint8 *buf, uint8 *table); -static void render_obj_im2(uint32 line, uint32 odd, uint8 *buf, uint8 *table); -static void render_bg(uint32 line, uint32 width); -static void render_bg_im2(uint32 line, uint32 width, uint32 odd); -static void render_bg_vs(uint32 line, uint32 width); +/*--------------------------------------------------------------------------*/ +/* Color update functions */ +/*--------------------------------------------------------------------------*/ + +static void palette_init(void); static void make_name_lut(void); static uint32 make_lut_bg(uint32 bx, uint32 ax); static uint32 make_lut_obj(uint32 bx, uint32 sx); static uint32 make_lut_bg_ste(uint32 bx, uint32 ax); static uint32 make_lut_obj_ste(uint32 bx, uint32 sx); static uint32 make_lut_bgobj_ste(uint32 bx, uint32 sx); +static void color_update_16(int index, uint16 data); +#ifndef NGC +static void color_update_8(int index, uint16 data); +static void color_update_15(int index, uint16 data); +static void color_update_32(int index, uint16 data); +static inline void remap_8(uint8 *src, uint8 *dst, uint8 *table, int length); +static inline void remap_16(uint8 *src, uint16 *dst, uint16 *table, int length); +static inline void remap_32(uint8 *src, uint32 *dst, uint32 *table, int length); +#else +static inline void remap_texture(uint8 *src, uint16 *dst, uint32 tiles); +#endif +static inline void merge(uint8 *srca, uint8 *srcb, uint8 *dst, uint8 *table, uint32 width); +static inline void update_bg_pattern_cache(uint32 index); +static inline uint32 get_hscroll(uint32 line); +static void render_bg(uint32 line, uint32 width); +static void render_bg_im2(uint32 line, uint32 width, uint32 odd); +static void render_bg_vs(uint32 line, uint32 width); +static void render_obj(uint32 line, uint8 *buf, uint8 *table); +static void render_obj_im2(uint32 line, uint32 odd, uint8 *buf, uint8 *table); #undef ALIGN_LONG #ifdef ALIGN_LONG @@ -423,53 +442,29 @@ static uint32 object_index_count; */ -uint8 rgb565_norm[2][8] = {{0 , 4, 9, 13, 18, 22, 27, 31}, - {0 , 9, 18, 27, 36, 45, 54, 63}}; -uint8 rgb565_half[2][8] = {{0 , 2, 4, 6, 9, 11, 13, 15}, - {0 , 4, 9, 13, 18, 22, 27, 31}}; -uint8 rgb565_high[2][8] = {{15, 17, 19, 21, 24, 26, 28, 31}, - {31, 35, 40, 44, 49, 53, 58, 63}}; - - -void palette_init(void) +static const uint8 rgb565_norm[2][8] = { - int i; + {0 , 4, 9, 13, 18, 22, 27, 31}, + {0 , 9, 18, 27, 36, 45, 54, 63} +}; - for (i = 0; i < 0x200; i += 1) - { - int r, g, b; +static const uint8 rgb565_half[2][8] = +{ + {0 , 2, 4, 6, 9, 11, 13, 15}, + {0 , 4, 9, 13, 18, 22, 27, 31} +}; - r = (i >> 6) & 7; - g = (i >> 3) & 7; - b = (i >> 0) & 7; - -#ifndef NGC - pixel_8_lut[0][i] = MAKE_PIXEL_8(r>>1,g>>1,b>>1); - pixel_8_lut[1][i] = MAKE_PIXEL_8(r,g,b); - pixel_8_lut[2][i] = MAKE_PIXEL_8((r>>1)|4,(g>>1)|4,(b>>1)|4); - - pixel_15_lut[0][i] = MAKE_PIXEL_15(r,g,b); - pixel_15_lut[1][i] = MAKE_PIXEL_15(r<<1,g<<1,b<<1); - pixel_15_lut[2][i] = MAKE_PIXEL_15(r|8,g|8,b|8); - - pixel_32_lut[0][i] = MAKE_PIXEL_32(r,g,b); - pixel_32_lut[1][i] = MAKE_PIXEL_32(r<<1,g<<1,b<<1); - pixel_32_lut[2][i] = MAKE_PIXEL_32(r|8,g|8,b|8); -#endif - - /* RGB 565 format: we extrapolate each 3-bit value into a 5-bit (R,B) or 6-bit (G) value - this is needed to correctly cover full color range: [0-31] for R,B or [0-63] for G */ - pixel_16_lut[0][i] = MAKE_PIXEL_16(rgb565_half[0][r],rgb565_half[1][g],rgb565_half[0][b]); - pixel_16_lut[1][i] = MAKE_PIXEL_16(rgb565_norm[0][r],rgb565_norm[1][g],rgb565_norm[0][b]); - pixel_16_lut[2][i] = MAKE_PIXEL_16(rgb565_high[0][r],rgb565_high[1][g],rgb565_high[0][b]); - } -} +static const uint8 rgb565_high[2][8] = +{ + {15, 17, 19, 21, 24, 26, 28, 31}, + {31, 35, 40, 44, 49, 53, 58, 63} +}; /*--------------------------------------------------------------------------*/ -/* Init, reset, shutdown routines */ +/* Init, reset, shutdown routines */ /*--------------------------------------------------------------------------*/ -int render_init (void) +void render_init(void) { int bx, ax, i; @@ -508,38 +503,6 @@ int render_init (void) /* Make sprite name look-up table */ make_name_lut(); - - return (1); -} - -void make_name_lut(void) -{ - int col, row; - int vcol, vrow; - int width, height; - int flipx, flipy; - int i, name; - - memset (name_lut, 0, sizeof (name_lut)); - - for (i = 0; i < 0x400; i += 1) - { - vcol = col = i & 3; - vrow = row = (i >> 2) & 3; - height = (i >> 4) & 3; - width = (i >> 6) & 3; - flipx = (i >> 8) & 1; - flipy = (i >> 9) & 1; - - if(flipx) vcol = (width - col); - if(flipy) vrow = (height - row); - - name = vrow + (vcol * (height + 1)); - - if ((row > height) || col > width) name = -1; - - name_lut[i] = name; - } } void render_reset(void) @@ -568,225 +531,21 @@ void render_shutdown(void) if(lut_base) free(lut_base); } -/*--------------------------------------------------------------------------*/ -/* Helper functions (cache update, hscroll, window clip) */ -/*--------------------------------------------------------------------------*/ - -static inline void update_bg_pattern_cache(uint32 index) -{ - int i; - uint8 x, y, c; - uint16 name; - uint8 *dst; - uint32 bp; -#ifdef LSB_FIRST - uint8 shift_table[8] = {12, 8, 4, 0, 28, 24, 20, 16}; -#else - uint8 shift_table[8] = {28, 24, 20, 16, 12, 8, 4, 0}; -#endif - - for(i = 0; i < index; i ++) - { - name = bg_name_list[i]; - bg_name_list[i] = 0; - - for(y = 0; y < 8; y ++) - { - if(bg_name_dirty[name] & (1 << y)) - { - dst = &bg_pattern_cache[name << 6]; - bp = *(uint32 *)&vram[(name << 5) | (y << 2)]; - - for(x = 0; x < 8; x ++) - { - c = (bp >> shift_table[x]) & 0x0F; - dst[0x00000 | (y << 3) | (x)] = (c); /* hf=0, vf=0: normal */ - dst[0x20000 | (y << 3) | (x ^ 7)] = (c); /* hf=1, vf=0: horizontal flipped */ - dst[0x40000 | ((y ^ 7) << 3) | (x)] = (c); /* hf=0, vf=1: vertical flipped */ - dst[0x60000 | ((y ^ 7) << 3) | (x ^ 7)] = (c); /* hf=1, vf=1: horizontal & vertical flipped */ - } - } - } - bg_name_dirty[name] = 0; - } -} - -static inline uint32 get_hscroll(uint32 line) -{ - switch(reg[11] & 3) - { - case 0: /* Full-screen */ - return *(uint32 *)&vram[hscb]; - - case 1: /* First 8 lines */ - return *(uint32 *)&vram[hscb + ((line & 7) << 2)]; - - case 2: /* Every 8 lines */ - return *(uint32 *)&vram[hscb + ((line & ~7) << 2)]; - - default: /* Every line */ - return *(uint32 *)&vram[hscb + (line << 2)]; - } -} - -/* Update Window Clipping (only called when registers change) */ -void window_clip(uint8 reg_12, uint8 reg_17) -{ - /* Window size and invert flags */ - int hp = (reg_17 & 0x1f); - int hf = (reg_17 >> 7) & 1; - - /* Display size */ - int sw = (reg_12 & 1) ? 20 : 16; - - /* Clear clipping data */ - memset(&clip, 0, sizeof(clip)); - - /* Perform horizontal clipping; the results are applied in reverse - if the horizontal inversion flag is set */ - int a = hf; - int w = hf ^ 1; - - if(hp) - { - if(hp > sw) - { - /* Plane W takes up entire line */ - clip[w].right = sw; - clip[w].enable = 1; - } - else - { - /* Window takes left side, Plane A takes right side */ - clip[w].right = hp; - clip[a].left = hp; - clip[a].right = sw; - clip[0].enable = clip[1].enable = 1; - } - } - else - { - /* Plane A takes up entire line */ - clip[a].right = sw; - clip[a].enable = 1; - } -} - -/*--------------------------------------------------------------------------*/ -/* Remap functions */ -/*--------------------------------------------------------------------------*/ - -#ifndef NGC -static inline void remap_8(uint8 *src, uint8 *dst, uint8 *table, int length) -{ - int count; - for(count = 0; count < length; count += 1) - { - *dst++ = table[*src++]; - } -} - -static inline void remap_16(uint8 *src, uint16 *dst, uint16 *table, int length) -{ - int count; - for(count = 0; count < length; count += 1) - { - *dst++ = table[*src++]; - } -} - -static inline void remap_32(uint8 *src, uint32 *dst, uint32 *table, int length) -{ - int count; - for(count = 0; count < length; count += 1) - { - *dst++ = table[*src++]; - } -} - -#else -static inline void remap_texture(uint8 *src, uint16 *dst, uint32 tiles) -{ - int count; - uint16 *table = pixel_16; - - for(count = 0; count < tiles; count ++) - { - /* one tile is 4 pixels wide */ - *dst++ = table[*src++]; - *dst++ = table[*src++]; - *dst++ = table[*src++]; - *dst++ = table[*src++]; - dst += 12; - } -} -#endif - - -static inline void merge(uint8 *srca, uint8 *srcb, uint8 *dst, uint8 *table, uint32 width) -{ - int i; - for(i = 0; i < width; i += 1) - { - *dst++ = table[(*srcb++ << 8) | (*srca++)]; - } -} /*--------------------------------------------------------------------------*/ /* Line render function */ /*--------------------------------------------------------------------------*/ -void remap_buffer(uint32 line, uint32 width) -{ - /* get line offset from framebuffer */ - line = (line + bitmap.viewport.y) % lines_per_frame; - - /* double resolution mode */ - if (config.render && interlaced) line = (line * 2) + odd_frame; - - /* NTSC Filter */ - if (config.ntsc) - { - if (reg[12]&1) md_ntsc_blit(&md_ntsc, ( MD_NTSC_IN_T const * )pixel_16, tmp_buf+0x20-bitmap.viewport.x, width, line); - else sms_ntsc_blit(&sms_ntsc, ( SMS_NTSC_IN_T const * )pixel_16, tmp_buf+0x20-bitmap.viewport.x, width, line); - return; - } - -#ifdef NGC - /* directly fill the RGB565 texture */ - /* one tile is 32 byte = 4x4 pixels */ - /* tiles are stored continuously in texture memory */ - width = width >> 2; - int offset = ((width << 5) * (line >> 2)) + ((line & 3) * 8); - remap_texture(tmp_buf+0x20-bitmap.viewport.x, (uint16 *)(texturemem + offset), width); - -#else - void *out =((void *)&bitmap.data[(line * bitmap.pitch)]); - switch(bitmap.depth) - { - case 8: - remap_8(tmp_buf+0x20-bitmap.viewport.x, (uint8 *)out, pixel_8, width); - break; - case 15: - remap_16(tmp_buf+0x20-bitmap.viewport.x, (uint16 *)out, pixel_15, width); - break; - case 16: - remap_16(tmp_buf+0x20-bitmap.viewport.x, (uint16 *)out, pixel_16, width); - break; - case 32: - remap_32(tmp_buf+0x20-bitmap.viewport.x, (uint32 *)out, pixel_32, width); - break; - } -#endif -} - void render_line(uint32 line, uint32 overscan) { uint32 width = bitmap.viewport.w; uint32 x_offset = bitmap.viewport.x; - /* background color (display OFF or borders) */ - if (overscan || !(reg[1] & 0x40)) + /* display OFF */ + if (!(reg[0] & 0x01)) return; + + /* background color (blanked display or vertical borders) */ + if (!(reg[1] & 0x40) || overscan) { width += 2 * x_offset; memset(&tmp_buf[0x20 - x_offset], 0x40, width); @@ -861,6 +620,679 @@ void render_line(uint32 line, uint32 overscan) remap_buffer(line,width); } +void remap_buffer(uint32 line, uint32 width) +{ + /* get line offset from framebuffer */ + line = (line + bitmap.viewport.y) % lines_per_frame; + + /* double resolution mode */ + if (config.render && interlaced) line = (line * 2) + odd_frame; + + /* NTSC Filter */ + if (config.ntsc) + { + if (reg[12]&1) md_ntsc_blit(&md_ntsc, ( MD_NTSC_IN_T const * )pixel_16, tmp_buf+0x20-bitmap.viewport.x, width, line); + else sms_ntsc_blit(&sms_ntsc, ( SMS_NTSC_IN_T const * )pixel_16, tmp_buf+0x20-bitmap.viewport.x, width, line); + return; + } + +#ifdef NGC + /* directly fill the RGB565 texture */ + /* one tile is 32 byte = 4x4 pixels */ + /* tiles are stored continuously in texture memory */ + width = width >> 2; + int offset = ((width << 5) * (line >> 2)) + ((line & 3) * 8); + remap_texture(tmp_buf+0x20-bitmap.viewport.x, (uint16 *)(texturemem + offset), width); + +#else + void *out =((void *)&bitmap.data[(line * bitmap.pitch)]); + switch(bitmap.depth) + { + case 8: + remap_8(tmp_buf+0x20-bitmap.viewport.x, (uint8 *)out, pixel_8, width); + break; + case 15: + remap_16(tmp_buf+0x20-bitmap.viewport.x, (uint16 *)out, pixel_15, width); + break; + case 16: + remap_16(tmp_buf+0x20-bitmap.viewport.x, (uint16 *)out, pixel_16, width); + break; + case 32: + remap_32(tmp_buf+0x20-bitmap.viewport.x, (uint32 *)out, pixel_32, width); + break; + } +#endif +} + +/* Update Window Clipping (only called when registers change) */ +void window_clip(void) +{ + /* Window size and invert flags */ + int hp = (reg[17] & 0x1f); + int hf = (reg[17] >> 7) & 1; + + /* Display size */ + int sw = bitmap.viewport.w >> 4; + + /* Clear clipping data */ + memset(&clip, 0, sizeof(clip)); + + /* Perform horizontal clipping; the results are applied in reverse + if the horizontal inversion flag is set */ + int a = hf; + int w = hf ^ 1; + + if(hp) + { + if(hp > sw) + { + /* Plane W takes up entire line */ + clip[w].right = sw; + clip[w].enable = 1; + } + else + { + /* Window takes left side, Plane A takes right side */ + clip[w].right = hp; + clip[a].left = hp; + clip[a].right = sw; + clip[0].enable = clip[1].enable = 1; + } + } + else + { + /* Plane A takes up entire line */ + clip[a].right = sw; + clip[a].enable = 1; + } +} + +/*--------------------------------------------------------------------------*/ +/* Sprites Parsing function */ +/*--------------------------------------------------------------------------*/ + +void parse_satb(uint32 line) +{ + uint8 sizetab[] = {8, 16, 24, 32}; + uint32 link = 0; + uint32 count, ypos, size, height; + + uint32 limit = (reg[12] & 1) ? 20 : 16; + uint32 total = limit << 2; + + uint16 *p = (uint16 *) &vram[satb]; + uint16 *q = (uint16 *) &sat[0]; + + object_index_count = 0; + + for(count = 0; count < total; count += 1) + { + ypos = (q[link] >> im2_flag) & 0x1FF; + size = q[link + 1] >> 8; + height = sizetab[size & 3]; + + if((line >= ypos) && (line < (ypos + height))) + { + /* sprite limit (max. 16 or 20 sprites displayed per line) */ + if(object_index_count == limit) + { + if(vint_pending == 0) status |= 0x40; + return; + } + + // using xpos from internal satb stops sprite x + // scrolling in bloodlin.bin, + // but this seems to go against the test prog + object_info[object_index_count].attr = p[link + 2]; + object_info[object_index_count].xpos = p[link + 3]; + object_info[object_index_count].ypos = ypos; + object_info[object_index_count].size = size; + ++object_index_count; + } + + link = (q[link + 1] & 0x7F) << 2; + if(link == 0) break; + } +} + +/*--------------------------------------------------------------------------*/ +/* Look-up table functions (handles priority between layers pixels) */ +/*--------------------------------------------------------------------------*/ + +static void palette_init(void) +{ + int i; + + for (i = 0; i < 0x200; i += 1) + { + int r, g, b; + + r = (i >> 6) & 7; + g = (i >> 3) & 7; + b = (i >> 0) & 7; + +#ifndef NGC + pixel_8_lut[0][i] = MAKE_PIXEL_8(r>>1,g>>1,b>>1); + pixel_8_lut[1][i] = MAKE_PIXEL_8(r,g,b); + pixel_8_lut[2][i] = MAKE_PIXEL_8((r>>1)|4,(g>>1)|4,(b>>1)|4); + + pixel_15_lut[0][i] = MAKE_PIXEL_15(r,g,b); + pixel_15_lut[1][i] = MAKE_PIXEL_15(r<<1,g<<1,b<<1); + pixel_15_lut[2][i] = MAKE_PIXEL_15(r|8,g|8,b|8); + + pixel_32_lut[0][i] = MAKE_PIXEL_32(r,g,b); + pixel_32_lut[1][i] = MAKE_PIXEL_32(r<<1,g<<1,b<<1); + pixel_32_lut[2][i] = MAKE_PIXEL_32(r|8,g|8,b|8); +#endif + + /* RGB 565 format: we extrapolate each 3-bit value into a 5-bit (R,B) or 6-bit (G) value + this is needed to correctly cover full color range: [0-31] for R,B or [0-63] for G */ + pixel_16_lut[0][i] = MAKE_PIXEL_16(rgb565_half[0][r],rgb565_half[1][g],rgb565_half[0][b]); + pixel_16_lut[1][i] = MAKE_PIXEL_16(rgb565_norm[0][r],rgb565_norm[1][g],rgb565_norm[0][b]); + pixel_16_lut[2][i] = MAKE_PIXEL_16(rgb565_high[0][r],rgb565_high[1][g],rgb565_high[0][b]); + } +} + +static void make_name_lut(void) +{ + int col, row; + int vcol, vrow; + int width, height; + int flipx, flipy; + int i, name; + + memset (name_lut, 0, sizeof (name_lut)); + + for (i = 0; i < 0x400; i += 1) + { + vcol = col = i & 3; + vrow = row = (i >> 2) & 3; + height = (i >> 4) & 3; + width = (i >> 6) & 3; + flipx = (i >> 8) & 1; + flipy = (i >> 9) & 1; + + if(flipx) vcol = (width - col); + if(flipy) vrow = (height - row); + + name = vrow + (vcol * (height + 1)); + + if ((row > height) || col > width) name = -1; + + name_lut[i] = name; + } +} + +/* Input (bx): d5-d0=color, d6=priority, d7=unused */ +/* Input (ax): d5-d0=color, d6=priority, d7=unused */ +/* Output: d5-d0=color, d6=priority, d7=unused */ +static uint32 make_lut_bg(uint32 bx, uint32 ax) +{ + int bf, bp, b; + int af, ap, a; + int x = 0; + int c; + + bf = (bx & 0x7F); + bp = (bx >> 6) & 1; + b = (bx & 0x0F); + + af = (ax & 0x7F); + ap = (ax >> 6) & 1; + a = (ax & 0x0F); + + c = (ap ? (a ? af : (b ? bf : x)) : \ + (bp ? (b ? bf : (a ? af : x)) : \ + ( (a ? af : (b ? bf : x)) ))); + + /* Strip palette bits from transparent pixels */ + if((c & 0x0F) == 0x00) c &= 0xC0; + + return (c); +} + + +/* Input (bx): d5-d0=color, d6=priority, d7=sprite pixel marker */ +/* Input (sx): d5-d0=color, d6=priority, d7=unused */ +/* Output: d5-d0=color, d6=zero, d7=sprite pixel marker */ +static uint32 make_lut_obj(uint32 bx, uint32 sx) +{ + int bf, bp, bs, b; + int sf, sp, s; + int c; + + bf = (bx & 0x3F); + bs = (bx >> 7) & 1; + bp = (bx >> 6) & 1; + b = (bx & 0x0F); + + sf = (sx & 0x3F); + sp = (sx >> 6) & 1; + s = (sx & 0x0F); + + if(s == 0) return bx; + + if(bs) + { + c = bf; /* previous sprite has higher priority */ + } + else + { + c = (sp ? (s ? sf : bf) : \ + (bp ? (b ? bf : (s ? sf : bf)) : \ + (s ? sf : bf) )); + } + + /* Strip palette bits from transparent pixels */ + if((c & 0x0F) == 0x00) c &= 0xC0; + + return (c | 0x80); +} + + +/* Input (bx): d5-d0=color, d6=priority, d7=unused */ +/* Input (sx): d5-d0=color, d6=priority, d7=unused */ +/* Output: d5-d0=color, d6=priority, d7=intensity select (half/normal) */ +static uint32 make_lut_bg_ste(uint32 bx, uint32 ax) +{ + int bf, bp, b; + int af, ap, a; + int gi; + int x = 0; + int c; + + bf = (bx & 0x7F); + bp = (bx >> 6) & 1; + b = (bx & 0x0F); + + af = (ax & 0x7F); + ap = (ax >> 6) & 1; + a = (ax & 0x0F); + + gi = (ap | bp) ? 0x80 : 0x00; + + c = (ap ? (a ? af : (b ? bf : x)) : + (bp ? (b ? bf : (a ? af : x)) : ((a ? af : (b ? bf : x))))); + + c |= gi; + + /* Strip palette bits from transparent pixels */ + if((c & 0x0F) == 0x00) c &= 0xC0; + + return (c); +} + + +/* Input (bx): d5-d0=color, d6=priority, d7=sprite pixel marker */ +/* Input (sx): d5-d0=color, d6=priority, d7=unused */ +/* Output: d5-d0=color, d6=priority, d7=sprite pixel marker */ +static uint32 make_lut_obj_ste(uint32 bx, uint32 sx) +{ + int bf, bs; + int sf; + int c; + + bf = (bx & 0x7F); + bs = (bx >> 7) & 1; + sf = (sx & 0x7F); + + if((sx & 0x0F) == 0) return bx; + + c = (bs) ? bf : sf; + + /* Strip palette bits from transparent pixels */ + if((c & 0x0F) == 0x00) c &= 0xC0; + + return (c | 0x80); +} + + +/* Input (bx): d5-d0=color, d6=priority, d7=intensity (half/normal) */ +/* Input (sx): d5-d0=color, d6=priority, d7=sprite marker */ +/* Output: d5-d0=color, d6=intensity (half/normal), d7=(double/invalid) */ +static uint32 make_lut_bgobj_ste(uint32 bx, uint32 sx) +{ + int c; + + int bf = (bx & 0x3F); + int bp = (bx >> 6) & 1; + int bi = (bx & 0x80) ? 0x40 : 0x00; + int b = (bx & 0x0F); + + int sf = (sx & 0x3F); + int sp = (sx >> 6) & 1; + int si = (sx & 0x40); + int s = (sx & 0x0F); + + if(bi & 0x40) si |= 0x40; + + if(sp) + { + if(s) + { + if((sf & 0x3E) == 0x3E) + { + if(sf & 1) + { + c = (bf | 0x00); + } + else + { + c = (bx & 0x80) ? (bf | 0x80) : (bf | 0x40); + } + } + else + { + if(sf == 0x0E || sf == 0x1E || sf == 0x2E) + { + c = (sf | 0x40); + } + else + { + c = (sf | si); + } + } + } + else + { + c = (bf | bi); + } + } + else + { + if(bp) + { + if(b) + { + c = (bf | bi); + } + else + { + if(s) + { + if((sf & 0x3E) == 0x3E) + { + if(sf & 1) + { + c = (bf | 0x00); + } + else + { + c = (bx & 0x80) ? (bf | 0x80) : (bf | 0x40); + } + } + else + { + if(sf == 0x0E || sf == 0x1E || sf == 0x2E) + { + c = (sf | 0x40); + } + else + { + c = (sf | si); + } + } + } + else + { + c = (bf | bi); + } + } + } + else + { + if(s) + { + if((sf & 0x3E) == 0x3E) + { + if(sf & 1) + { + c = (bf | 0x00); + } + else + { + c = (bx & 0x80) ? (bf | 0x80) : (bf | 0x40); + } + } + else + { + if(sf == 0x0E || sf == 0x1E || sf == 0x2E) + { + c = (sf | 0x40); + } + else + { + c = (sf | si); + } + } + } + else + { + c = (bf | bi); + } + } + } + + if((c & 0x0f) == 0x00) c &= 0xC0; + + return (c); +} + +/*--------------------------------------------------------------------------*/ +/* Color update functions */ +/*--------------------------------------------------------------------------*/ +#ifndef NGC + +static void color_update_8(int index, uint16 data) +{ + /* Palette Selection bit */ + if (!(reg[0] & 4)) data &= 0x49; + + if(reg[12] & 8) + { + pixel_8[0x00 | index] = pixel_8_lut[0][data]; + pixel_8[0x40 | index] = pixel_8_lut[1][data]; + pixel_8[0x80 | index] = pixel_8_lut[2][data]; + } + else + { + uint8 temp = pixel_8_lut[1][data]; + pixel_8[0x00 | index] = temp; + pixel_8[0x40 | index] = temp; + pixel_8[0x80 | index] = temp; + } +} + +static void color_update_15(int index, uint16 data) +{ + /* Palette Selection bit */ + if (!(reg[0] & 4)) data &= 0x49; + + if(reg[12] & 8) + { + pixel_15[0x00 | index] = pixel_15_lut[0][data]; + pixel_15[0x40 | index] = pixel_15_lut[1][data]; + pixel_15[0x80 | index] = pixel_15_lut[2][data]; + } + else + { + uint16 temp = pixel_15_lut[1][data]; + pixel_15[0x00 | index] = temp; + pixel_15[0x40 | index] = temp; + pixel_15[0x80 | index] = temp; + } +} + +static void color_update_32(int index, uint16 data) +{ + /* Palette Selection bit */ + if (!(reg[0] & 4)) data &= 0x49; + + if(reg[12] & 8) + { + pixel_32[0x00 | index] = pixel_32_lut[0][data]; + pixel_32[0x40 | index] = pixel_32_lut[1][data]; + pixel_32[0x80 | index] = pixel_32_lut[2][data]; + } + else + { + uint32 temp = pixel_32_lut[1][data]; + pixel_32[0x00 | index] = temp; + pixel_32[0x40 | index] = temp; + pixel_32[0x80 | index] = temp; + } +} + +#endif + +static void color_update_16(int index, uint16 data) +{ + /* Palette Selection bit */ + if (!(reg[0] & 4)) data &= 0x49; + + if(reg[12] & 8) + { + pixel_16[0x00 | index] = pixel_16_lut[0][data]; + pixel_16[0x40 | index] = pixel_16_lut[1][data]; + pixel_16[0x80 | index] = pixel_16_lut[2][data]; + } + else + { + uint16 temp = pixel_16_lut[1][data]; + pixel_16[0x00 | index] = temp; + pixel_16[0x40 | index] = temp; + pixel_16[0x80 | index] = temp; + } +} + +/*--------------------------------------------------------------------------*/ +/* Remap functions */ +/*--------------------------------------------------------------------------*/ + +#ifndef NGC + +static inline void remap_8(uint8 *src, uint8 *dst, uint8 *table, int length) +{ + int count; + for(count = 0; count < length; count += 1) + { + *dst++ = table[*src++]; + } +} + +static inline void remap_16(uint8 *src, uint16 *dst, uint16 *table, int length) +{ + int count; + for(count = 0; count < length; count += 1) + { + *dst++ = table[*src++]; + } +} + +static inline void remap_32(uint8 *src, uint32 *dst, uint32 *table, int length) +{ + int count; + for(count = 0; count < length; count += 1) + { + *dst++ = table[*src++]; + } +} + +#else + +static inline void remap_texture(uint8 *src, uint16 *dst, uint32 tiles) +{ + int count; + uint16 *table = pixel_16; + + for(count = 0; count < tiles; count ++) + { + /* one tile is 4 pixels wide */ + *dst++ = table[*src++]; + *dst++ = table[*src++]; + *dst++ = table[*src++]; + *dst++ = table[*src++]; + dst += 12; + } +} +#endif + + +static inline void merge(uint8 *srca, uint8 *srcb, uint8 *dst, uint8 *table, uint32 width) +{ + int i; + for(i = 0; i < width; i += 1) + { + *dst++ = table[(*srcb++ << 8) | (*srca++)]; + } +} + +/*--------------------------------------------------------------------------*/ +/* Helper functions (cache update, hscroll, window clip) */ +/*--------------------------------------------------------------------------*/ + +static inline void update_bg_pattern_cache(uint32 index) +{ + int i; + uint8 x, y, c; + uint16 name; + uint8 *dst; + uint32 bp; +#ifdef LSB_FIRST + uint8 shift_table[8] = {12, 8, 4, 0, 28, 24, 20, 16}; +#else + uint8 shift_table[8] = {28, 24, 20, 16, 12, 8, 4, 0}; +#endif + + for(i = 0; i < index; i ++) + { + name = bg_name_list[i]; + bg_name_list[i] = 0; + + for(y = 0; y < 8; y ++) + { + if(bg_name_dirty[name] & (1 << y)) + { + dst = &bg_pattern_cache[name << 6]; + bp = *(uint32 *)&vram[(name << 5) | (y << 2)]; + + for(x = 0; x < 8; x ++) + { + c = (bp >> shift_table[x]) & 0x0F; + dst[0x00000 | (y << 3) | (x)] = (c); /* hf=0, vf=0: normal */ + dst[0x20000 | (y << 3) | (x ^ 7)] = (c); /* hf=1, vf=0: horizontal flipped */ + dst[0x40000 | ((y ^ 7) << 3) | (x)] = (c); /* hf=0, vf=1: vertical flipped */ + dst[0x60000 | ((y ^ 7) << 3) | (x ^ 7)] = (c); /* hf=1, vf=1: horizontal & vertical flipped */ + } + } + } + bg_name_dirty[name] = 0; + } +} + +static inline uint32 get_hscroll(uint32 line) +{ + switch(reg[11] & 3) + { + case 0: /* Full-screen */ + return *(uint32 *)&vram[hscb]; + + case 1: /* First 8 lines */ + return *(uint32 *)&vram[hscb + ((line & 7) << 2)]; + + case 2: /* Every 8 lines */ + return *(uint32 *)&vram[hscb + ((line & ~7) << 2)]; + + default: /* Every line */ + return *(uint32 *)&vram[hscb + (line << 2)]; + } +} + + +/*--------------------------------------------------------------------------*/ +/* Layers render functions */ +/*--------------------------------------------------------------------------*/ + static void render_bg(uint32 line, uint32 width) { uint32 column, atex, atbuf, *src, *dst; @@ -1238,387 +1670,9 @@ static void render_bg_im2(uint32 line, uint32 width, uint32 odd) /*--------------------------------------------------------------------------*/ -/* Look-up table functions (handles priority between layers pixels) */ +/* Object render functions */ /*--------------------------------------------------------------------------*/ -/* Input (bx): d5-d0=color, d6=priority, d7=unused */ -/* Input (ax): d5-d0=color, d6=priority, d7=unused */ -/* Output: d5-d0=color, d6=priority, d7=unused */ -static uint32 make_lut_bg(uint32 bx, uint32 ax) -{ - int bf, bp, b; - int af, ap, a; - int x = 0; - int c; - - bf = (bx & 0x7F); - bp = (bx >> 6) & 1; - b = (bx & 0x0F); - - af = (ax & 0x7F); - ap = (ax >> 6) & 1; - a = (ax & 0x0F); - - c = (ap ? (a ? af : (b ? bf : x)) : \ - (bp ? (b ? bf : (a ? af : x)) : \ - ( (a ? af : (b ? bf : x)) ))); - - /* Strip palette bits from transparent pixels */ - if((c & 0x0F) == 0x00) c &= 0xC0; - - return (c); -} - - -/* Input (bx): d5-d0=color, d6=priority, d7=sprite pixel marker */ -/* Input (sx): d5-d0=color, d6=priority, d7=unused */ -/* Output: d5-d0=color, d6=zero, d7=sprite pixel marker */ -static uint32 make_lut_obj(uint32 bx, uint32 sx) -{ - int bf, bp, bs, b; - int sf, sp, s; - int c; - - bf = (bx & 0x3F); - bs = (bx >> 7) & 1; - bp = (bx >> 6) & 1; - b = (bx & 0x0F); - - sf = (sx & 0x3F); - sp = (sx >> 6) & 1; - s = (sx & 0x0F); - - if(s == 0) return bx; - - if(bs) - { - c = bf; /* previous sprite has higher priority */ - } - else - { - c = (sp ? (s ? sf : bf) : \ - (bp ? (b ? bf : (s ? sf : bf)) : \ - (s ? sf : bf) )); - } - - /* Strip palette bits from transparent pixels */ - if((c & 0x0F) == 0x00) c &= 0xC0; - - return (c | 0x80); -} - - -/* Input (bx): d5-d0=color, d6=priority, d7=unused */ -/* Input (sx): d5-d0=color, d6=priority, d7=unused */ -/* Output: d5-d0=color, d6=priority, d7=intensity select (half/normal) */ -static uint32 make_lut_bg_ste(uint32 bx, uint32 ax) -{ - int bf, bp, b; - int af, ap, a; - int gi; - int x = 0; - int c; - - bf = (bx & 0x7F); - bp = (bx >> 6) & 1; - b = (bx & 0x0F); - - af = (ax & 0x7F); - ap = (ax >> 6) & 1; - a = (ax & 0x0F); - - gi = (ap | bp) ? 0x80 : 0x00; - - c = (ap ? (a ? af : (b ? bf : x)) : - (bp ? (b ? bf : (a ? af : x)) : ((a ? af : (b ? bf : x))))); - - c |= gi; - - /* Strip palette bits from transparent pixels */ - if((c & 0x0F) == 0x00) c &= 0xC0; - - return (c); -} - - -/* Input (bx): d5-d0=color, d6=priority, d7=sprite pixel marker */ -/* Input (sx): d5-d0=color, d6=priority, d7=unused */ -/* Output: d5-d0=color, d6=priority, d7=sprite pixel marker */ -static uint32 make_lut_obj_ste(uint32 bx, uint32 sx) -{ - int bf, bs; - int sf; - int c; - - bf = (bx & 0x7F); - bs = (bx >> 7) & 1; - sf = (sx & 0x7F); - - if((sx & 0x0F) == 0) return bx; - - c = (bs) ? bf : sf; - - /* Strip palette bits from transparent pixels */ - if((c & 0x0F) == 0x00) c &= 0xC0; - - return (c | 0x80); -} - - -/* Input (bx): d5-d0=color, d6=priority, d7=intensity (half/normal) */ -/* Input (sx): d5-d0=color, d6=priority, d7=sprite marker */ -/* Output: d5-d0=color, d6=intensity (half/normal), d7=(double/invalid) */ -static uint32 make_lut_bgobj_ste(uint32 bx, uint32 sx) -{ - int c; - - int bf = (bx & 0x3F); - int bp = (bx >> 6) & 1; - int bi = (bx & 0x80) ? 0x40 : 0x00; - int b = (bx & 0x0F); - - int sf = (sx & 0x3F); - int sp = (sx >> 6) & 1; - int si = (sx & 0x40); - int s = (sx & 0x0F); - - if(bi & 0x40) si |= 0x40; - - if(sp) - { - if(s) - { - if((sf & 0x3E) == 0x3E) - { - if(sf & 1) - { - c = (bf | 0x00); - } - else - { - c = (bx & 0x80) ? (bf | 0x80) : (bf | 0x40); - } - } - else - { - if(sf == 0x0E || sf == 0x1E || sf == 0x2E) - { - c = (sf | 0x40); - } - else - { - c = (sf | si); - } - } - } - else - { - c = (bf | bi); - } - } - else - { - if(bp) - { - if(b) - { - c = (bf | bi); - } - else - { - if(s) - { - if((sf & 0x3E) == 0x3E) - { - if(sf & 1) - { - c = (bf | 0x00); - } - else - { - c = (bx & 0x80) ? (bf | 0x80) : (bf | 0x40); - } - } - else - { - if(sf == 0x0E || sf == 0x1E || sf == 0x2E) - { - c = (sf | 0x40); - } - else - { - c = (sf | si); - } - } - } - else - { - c = (bf | bi); - } - } - } - else - { - if(s) - { - if((sf & 0x3E) == 0x3E) - { - if(sf & 1) - { - c = (bf | 0x00); - } - else - { - c = (bx & 0x80) ? (bf | 0x80) : (bf | 0x40); - } - } - else - { - if(sf == 0x0E || sf == 0x1E || sf == 0x2E) - { - c = (sf | 0x40); - } - else - { - c = (sf | si); - } - } - } - else - { - c = (bf | bi); - } - } - } - - if((c & 0x0f) == 0x00) c &= 0xC0; - - return (c); -} - -/*--------------------------------------------------------------------------*/ -/* Color update functions */ -/*--------------------------------------------------------------------------*/ -#ifndef NGC - -void color_update_8(int index, uint16 data) -{ - if(reg[12] & 8) - { - pixel_8[0x00 | index] = pixel_8_lut[0][data]; - pixel_8[0x40 | index] = pixel_8_lut[1][data]; - pixel_8[0x80 | index] = pixel_8_lut[2][data]; - } - else - { - uint8 temp = pixel_8_lut[1][data]; - pixel_8[0x00 | index] = temp; - pixel_8[0x40 | index] = temp; - pixel_8[0x80 | index] = temp; - } -} - -void color_update_15(int index, uint16 data) -{ - if(reg[12] & 8) - { - pixel_15[0x00 | index] = pixel_15_lut[0][data]; - pixel_15[0x40 | index] = pixel_15_lut[1][data]; - pixel_15[0x80 | index] = pixel_15_lut[2][data]; - } - else - { - uint16 temp = pixel_15_lut[1][data]; - pixel_15[0x00 | index] = temp; - pixel_15[0x40 | index] = temp; - pixel_15[0x80 | index] = temp; - } -} - -void color_update_32(int index, uint16 data) -{ - if(reg[12] & 8) - { - pixel_32[0x00 | index] = pixel_32_lut[0][data]; - pixel_32[0x40 | index] = pixel_32_lut[1][data]; - pixel_32[0x80 | index] = pixel_32_lut[2][data]; - } - else - { - uint32 temp = pixel_32_lut[1][data]; - pixel_32[0x00 | index] = temp; - pixel_32[0x40 | index] = temp; - pixel_32[0x80 | index] = temp; - } -} - -#endif - -void color_update_16(int index, uint16 data) -{ - if(reg[12] & 8) - { - pixel_16[0x00 | index] = pixel_16_lut[0][data]; - pixel_16[0x40 | index] = pixel_16_lut[1][data]; - pixel_16[0x80 | index] = pixel_16_lut[2][data]; - } - else - { - uint16 temp = pixel_16_lut[1][data]; - pixel_16[0x00 | index] = temp; - pixel_16[0x40 | index] = temp; - pixel_16[0x80 | index] = temp; - } -} - -/*--------------------------------------------------------------------------*/ -/* Object render functions */ -/*--------------------------------------------------------------------------*/ - -void parse_satb(uint32 line) -{ - uint8 sizetab[] = {8, 16, 24, 32}; - uint32 link = 0; - uint32 count, ypos, size, height; - - uint32 limit = (reg[12] & 1) ? 20 : 16; - uint32 total = limit << 2; - - uint16 *p = (uint16 *) &vram[satb]; - uint16 *q = (uint16 *) &sat[0]; - - object_index_count = 0; - - for(count = 0; count < total; count += 1) - { - ypos = (q[link] >> im2_flag) & 0x1FF; - size = q[link + 1] >> 8; - height = sizetab[size & 3]; - - if((line >= ypos) && (line < (ypos + height))) - { - /* sprite limit (max. 16 or 20 sprites displayed per line) */ - if(object_index_count == limit) - { - if(vint_pending == 0) status |= 0x40; - return; - } - - // using xpos from internal satb stops sprite x - // scrolling in bloodlin.bin, - // but this seems to go against the test prog - object_info[object_index_count].attr = p[link + 2]; - object_info[object_index_count].xpos = p[link + 3]; - object_info[object_index_count].ypos = ypos; - object_info[object_index_count].size = size; - ++object_index_count; - } - - link = (q[link + 1] & 0x7F) << 2; - if(link == 0) break; - } -} - static int spr_over = 0; static void render_obj(uint32 line, uint8 *buf, uint8 *table) diff --git a/source/render.h b/source/render.h index e61be7f..dd06829 100644 --- a/source/render.h +++ b/source/render.h @@ -24,27 +24,14 @@ #ifndef _RENDER_H_ #define _RENDER_H_ -/* Global variables */ -extern uint8 rgb565_norm[2][8]; -extern uint8 rgb565_half[2][8]; -extern uint8 rgb565_high[2][8]; - /* Function prototypes */ -extern int render_init(void); -extern void palette_init(void); +extern void render_init(void); extern void render_reset(void); extern void render_shutdown(void); extern void render_line(uint32 line, uint32 overscan); -extern void parse_satb(uint32 line); extern void remap_buffer(uint32 line,uint32 width); -extern void window_clip(uint8 reg_12, uint8 reg_17); - -#ifndef NGC -extern void color_update_8(int index, uint16 data); -extern void color_update_15(int index, uint16 data); -extern void color_update_32(int index, uint16 data); -#endif -extern void color_update_16(int index, uint16 data); +extern void window_clip(void); +extern void parse_satb(uint32 line); void (*color_update)(int index, uint16 data); diff --git a/source/system.c b/source/system.c index d9b82d8..590aeb2 100644 --- a/source/system.c +++ b/source/system.c @@ -335,7 +335,7 @@ int system_frame (int do_skip) bitmap.viewport.changed = 1; /* Update clipping */ - window_clip(reg[12],reg[17]); + window_clip(); } #endif @@ -399,7 +399,7 @@ int system_frame (int do_skip) if ((line < vdp_height) && (h_counter == 0)) aim_m68k -= 36; /* update DMA timings */ - if (dma_length) dma_update(); + if (dma_length) vdp_update_dma(); /* vertical retrace */ if (line == vdp_height) @@ -443,7 +443,7 @@ int system_frame (int do_skip) else { /* update DMA timings */ - if (dma_length) dma_update(); + if (dma_length) vdp_update_dma(); /* render overscan */ if ((!do_skip) && ((line < end_line) || (line >= start_line))) render_line(line, 1); diff --git a/source/unused/win/config.c b/source/unused/win/config.c index b560b8c..b8d58fb 100644 --- a/source/unused/win/config.c +++ b/source/unused/win/config.c @@ -7,12 +7,11 @@ t_config config; void set_config_defaults(void) { /* sound options */ - config.psg_preamp = 1.5; - config.fm_preamp = 1.0; + config.psg_preamp = 150; + config.fm_preamp = 100; config.boost = 1; config.filter = 1; config.hq_fm = 1; - config.fm_core = 1; /* system options */ config.region_detect = 0; diff --git a/source/vdp.c b/source/vdp.c index 2b8ff1b..d4f34a3 100644 --- a/source/vdp.c +++ b/source/vdp.c @@ -126,9 +126,15 @@ static const uint32 dma_rates[16] = { 8, 83, 9, 102, /* DMA Copy */ }; -/* Function prototypes */ -static inline void data_write(unsigned int data); -static inline void vdp_reg_w(unsigned int r, unsigned int d); +/*--------------------------------------------------------------------------*/ +/* Functions prototype */ +/*--------------------------------------------------------------------------*/ +static inline void fifo_update(); +static inline void data_w(unsigned int data); +static inline void reg_w(unsigned int r, unsigned int d); +static inline void dma_copy(void); +static inline void dma_vbus (void); +static inline void dma_fill(unsigned int data); /*--------------------------------------------------------------------------*/ /* Init, reset, shutdown functions */ @@ -212,11 +218,10 @@ void vdp_reset(void) /* initialize some registers (normally set by BIOS) */ if (config.bios_enabled != 3) { - vdp_reg_w(1 , 0x04); /* Mode 5 enabled */ - vdp_reg_w(10, 0xff); /* HINT disabled */ - vdp_reg_w(12, 0x81); /* H40 mode */ - vdp_reg_w(15, 0x02); /* auto increment */ - window_clip(1,0); + reg_w(1 , 0x04); /* Mode 5 enabled */ + reg_w(10, 0xff); /* HINT disabled */ + reg_w(12, 0x81); /* H40 mode */ + reg_w(15, 0x02); /* auto increment */ } /* default latency */ @@ -232,7 +237,7 @@ void vdp_restore(uint8 *vdp_regs) for (i=0;i<0x20;i++) { - vdp_reg_w(i, vdp_regs[i]); + reg_w(i, vdp_regs[i]); } /* reinitialize HVC tables */ @@ -257,16 +262,19 @@ void vdp_restore(uint8 *vdp_regs) bg_list_index=0x800; /* reinitialize palette */ - for(i = 0; i < 0x40; i += 1) color_update(i, *(uint16 *)&cram[i << 1]); color_update(0x00, *(uint16 *)&cram[border << 1]); + for(i = 1; i < 0x40; i += 1) + { + color_update(i, *(uint16 *)&cram[i << 1]); + } } + /*--------------------------------------------------------------------------*/ -/* DMA Operations */ +/* DMA Timings update */ /*--------------------------------------------------------------------------*/ -/* Update DMA timings (this is call on start of DMA and then at the start of each scanline) */ -void dma_update() +void vdp_update_dma() { int dma_cycles = 0; @@ -316,232 +324,9 @@ void dma_update() } } -/* DMA Copy - Read byte from VRAM (source), write to VRAM (addr), - bump source and add r15 to addr. - - - see how source addr is affected - (can it make high source byte inc?) -*/ -static inline void dma_copy(void) -{ - int name; - int length = (reg[20] << 8 | reg[19]) & 0xFFFF; - int source = (reg[22] << 8 | reg[21]) & 0xFFFF; - if (!length) length = 0x10000; - - dma_type = 3; - dma_length = length; - dma_update(); - - /* proceed DMA */ - do - { - vram[addr] = vram[source]; - MARK_BG_DIRTY(addr); - source = (source + 1) & 0xFFFF; - addr += reg[15]; - } while (--length); - - /* update length & source address registers */ - reg[19] = length & 0xFF; - reg[20] = (length >> 8) & 0xFF; - reg[21] = source & 0xFF; /* not sure */ - reg[22] = (source >> 8) & 0xFF; -} - - -/* 68K Copy to VRAM, VSRAM or CRAM */ -static inline void dma_vbus (void) -{ - uint32 base, source = ((reg[23] & 0x7F) << 17 | reg[22] << 9 | reg[21] << 1) & 0xFFFFFE; - uint32 length = (reg[20] << 8 | reg[19]) & 0xFFFF; - uint32 temp; - - if (!length) length = 0x10000; - base = source; - - /* DMA timings */ - dma_type = (code & 0x06) ? 1 : 0; - dma_length = length; - dma_update(); - - /* DMA source */ - if ((source >> 17) == 0x50) - { - /* Z80 & I/O area */ - do - { - /* Return $FFFF only when the Z80 isn't hogging the Z-bus. - (e.g. Z80 isn't reset and 68000 has the bus) */ - if (source <= 0xa0ffff) temp = (zbusack ? *(uint16 *)(work_ram + (source & 0xffff)) : 0xffff); - - /* The I/O chip and work RAM try to drive the data bus which results - in both values being combined in random ways when read. - We return the I/O chip values which seem to have precedence, */ - else if (source <= 0xa1001f) - { - temp = io_read((source >> 1) & 0x0f); - temp = (temp << 8 | temp); - } - - /* All remaining locations access work RAM */ - else temp = *(uint16 *)(work_ram + (source & 0xffff)); - - source += 2; - source = ((base & 0xFE0000) | (source & 0x1FFFF)); - data_write (temp); - } - while (--length); - } - else - { - /* SVP latency */ - if (svp && (source < 0x400000)) - { - source = (source - 2); - } - - /* ROM & RAM */ - do - { - temp = *(uint16 *)(m68k_memory_map[source>>16].base + (source & 0xffff)); - source += 2; - source = ((base & 0xFE0000) | (source & 0x1FFFF)); - data_write (temp); - } - while (--length); - } - - /* update length & source address registers */ - reg[19] = length & 0xFF; - reg[20] = (length >> 8) & 0xFF; - reg[21] = (source >> 1) & 0xFF; - reg[22] = (source >> 9) & 0xFF; - reg[23] = (reg[23] & 0x80) | ((source >> 17) & 0x7F); -} - -/* VRAM FILL */ -static inline void dma_fill(unsigned int data) -{ - int name; - int length = (reg[20] << 8 | reg[19]) & 0xFFFF; - if (!length) length = 0x10000; - - /* DMA timings */ - dma_type = 2; - dma_length = length; - dma_update(); - - /* proceed DMA */ - data_write(data); - - /* write MSB */ - data = (data >> 8) & 0xff; - - /* detect internal SAT modification */ - if ((addr & sat_base_mask) == satb) - { - do - { - /* update internal SAT (fix Battletech) */ - WRITE_BYTE(sat, (addr & sat_addr_mask)^1, data); - WRITE_BYTE(vram, addr^1, data); - MARK_BG_DIRTY (addr); - addr += reg[15]; - } - while (--length); - } - else - { - do - { - WRITE_BYTE(vram, addr^1, data); - MARK_BG_DIRTY (addr); - addr += reg[15]; - } - while (--length); - } - - /* update length register */ - reg[19] = length & 0xFF; - reg[20] = (length >> 8) & 0xFF; - dmafill = 0; -} - /*--------------------------------------------------------------------------*/ -/* FIFO emulation */ +/* VDP Ports handler */ /*--------------------------------------------------------------------------*/ -static inline void fifo_update() -{ - if (fifo_write_cnt > 0) - { - /* update FIFO reads */ - uint32 fifo_read = ((count_m68k - fifo_lastwrite) / fifo_latency); - if (fifo_read > 0) - { - fifo_write_cnt -= fifo_read; - if (fifo_write_cnt < 0) fifo_write_cnt = 0; - - /* update cycle count */ - fifo_lastwrite += fifo_read*fifo_latency; - } - } -} - -/*--------------------------------------------------------------------------*/ -/* Memory access functions */ -/*--------------------------------------------------------------------------*/ -static inline void data_write (unsigned int data) -{ - switch (code & 0x0F) - { - case 0x01: /* VRAM */ - - /* Byte-swap data if A0 is set */ - if (addr & 1) data = (data >> 8) | (data << 8); - - /* Copy SAT data to the internal SAT */ - if ((addr & sat_base_mask) == satb) - { - *(uint16 *) &sat[addr & sat_addr_mask & 0xFFFE] = data; - } - - /* Only write unique data to VRAM */ - if (data != *(uint16 *) &vram[addr & 0xFFFE]) - { - /* Write data to VRAM */ - *(uint16 *) &vram[addr & 0xFFFE] = data; - - /* Update the pattern cache */ - int name; - MARK_BG_DIRTY (addr); - } - break; - - case 0x03: /* CRAM */ - { - uint16 *p = (uint16 *) &cram[(addr & 0x7E)]; - data = PACK_CRAM (data & 0x0EEE); - if (data != *p) - { - int index = (addr >> 1) & 0x3F; - *p = data; - color_update (index, *p); - color_update (0x00, *(uint16 *)&cram[border << 1]); - } - break; - } - - case 0x05: /* VSRAM */ - *(uint16 *) &vsram[(addr & 0x7E)] = data; - break; - } - - /* Increment address register */ - addr += reg[15]; -} - void vdp_ctrl_w(unsigned int data) { @@ -552,7 +337,7 @@ void vdp_ctrl_w(unsigned int data) /* VDP register write */ uint8 r = (data >> 8) & 0x1F; uint8 d = data & 0xFF; - vdp_reg_w (r, d); + reg_w(r, d); } else pending = 1; @@ -607,167 +392,6 @@ void vdp_ctrl_w(unsigned int data) if ((code & 0x0F) == 0x01) fifo_latency = fifo_latency * 2; } - -/* - The reg[] array is updated at the *end* of this function, so the new - register data can be compared with the previous data. -*/ -static inline void vdp_reg_w(unsigned int r, unsigned int d) -{ - /* Check if Mode 4 (SMS mode) has been activated - According to official doc, VDP registers #11 to #23 can not be written unless bit2 in register #1 is set - Fix Captain Planet & Avengers (Alt version), Bass Master Classic Pro Edition (they incidentally activate Mode 4) - */ - if (!(reg[1] & 4) && (r > 10)) return; - - switch(r) - { - case 0x00: /* CTRL #1 */ - if (hint_pending && ((d&0x10) != (reg[0]&0x10))) - { - /* update IRQ status */ - irq_status &= 0x20; - irq_status |= 0x10; - if (vint_pending && (reg[1] & 0x20)) irq_status |= 6; - else if (d & 0x10) irq_status |= 4; - } - break; - - case 0x01: /* CTRL #2 */ - if (vint_pending && ((d&0x20) != (reg[1]&0x20))) - { - /* update IRQ status */ - irq_status &= 0x20; - irq_status |= 0x110; - if (d & 0x20) irq_status |= 6; - else if (hint_pending && (reg[0] & 0x10)) irq_status |= 4; - } - - /* Check if the viewport height has actually been changed */ - if((reg[1] & 8) != (d & 8)) - { - /* Update the height of the viewport */ - bitmap.viewport.h = (d & 8) ? 240 : 224; - if (config.overscan) bitmap.viewport.y = ((vdp_pal ? 288 : 240) - bitmap.viewport.h) / 2; - bitmap.viewport.changed |= 1; - - /* update VC table */ - if (vdp_pal) vctab = (d & 8) ? vc_pal_240 : vc_pal_224; - } - - /* DISPLAY switched ON/OFF during HBLANK */ - if ((v_counter < bitmap.viewport.h) && ((d&0x40) != (reg[1]&0x40))) - { - if (count_m68k <= (hint_m68k + 120)) - { - /* Redraw the current line : - - Legend of Galahad, Lemmings 2, Nigel Mansell's World Championship Racing (set display OFF) - - Deadly Moves aka Power Athlete (set display ON) - */ - reg[1] = d; - render_line(v_counter, 0); - } - } - break; - - case 0x02: /* NTAB */ - ntab = (d << 10) & 0xE000; - break; - - case 0x03: /* NTWB */ - ntwb = (d << 10) & 0xF800; - if(reg[12] & 1) ntwb &= 0xF000; - break; - - case 0x04: /* NTBB */ - ntbb = (d << 13) & 0xE000; - break; - - case 0x05: /* SATB */ - sat_base_mask = (reg[12] & 1) ? 0xFC00 : 0xFE00; - sat_addr_mask = (reg[12] & 1) ? 0x03FF : 0x01FF; - satb = (d << 9) & sat_base_mask; - break; - - case 0x07: /* Border Color index */ - /* Check if the border color has actually changed */ - d &= 0x3F; - if(border != d) - { - /* Mark the border color as modified */ - border = d; - color_update(0x00, *(uint16 *)&cram[(border << 1)]); - - /* background color modified during HBLANK */ - if ((v_counter < bitmap.viewport.h) && (count_m68k <= (line_m68k + 84))) - { - /* remap current line (see Road Rash I,II,III) */ - reg[7] = d; - remap_buffer(v_counter,bitmap.viewport.w + 2*bitmap.viewport.x); - } - } - break; - - case 0x0C: - /* Check if the viewport width has actually been changed */ - if((reg[0x0C] & 1) != (d & 1)) - { -#ifndef NGC - /* Update the width of the viewport */ - bitmap.viewport.w = (d & 1) ? 320 : 256; - bitmap.viewport.changed = 1; - - /* Update clipping */ - window_clip(d,reg[17]); -#else - /* Postpound update on next frame */ - bitmap.viewport.changed = 2; -#endif - /* update HC table */ - hctab = (d & 1) ? cycle2hc40 : cycle2hc32; - } - - /* See if the S/TE mode bit has changed */ - if((reg[0x0C] & 8) != (d & 8)) - { - int i; - - /* The following color update check this value */ - reg[0x0C] = d; - - /* Update colors */ - for (i = 0; i < 0x40; i += 1) color_update (i, *(uint16 *) & cram[i << 1]); - color_update (0x00, *(uint16 *) & cram[border << 1]); - } - - /* The following register updates check this value */ - reg[0x0C] = d; - - /* Update display-dependant registers */ - vdp_reg_w(0x03, reg[0x03]); - vdp_reg_w(0x05, reg[0x05]); - break; - - case 0x0D: /* HSCB */ - hscb = (d << 10) & 0xFC00; - break; - - case 0x10: /* Playfield size */ - playfield_shift = shift_table[(d & 3)]; - playfield_col_mask = col_mask_table[(d & 3)]; - playfield_row_mask = row_mask_table[(d >> 4) & 3]; - y_mask = y_mask_table[(d & 3)]; - break; - - case 0x11: /* update clipping */ - window_clip(reg[12],d); - break; - } - - /* Write new register value */ - reg[r] = d; -} - /* * Return VDP status * @@ -857,7 +481,7 @@ void vdp_data_w(unsigned int data) } /* write data */ - data_write(data); + data_w(data); } unsigned int vdp_data_r(void) @@ -901,7 +525,6 @@ unsigned int vdp_hvc_r(void) return ((vc << 8) | hc); } - void vdp_test_w(unsigned int value) { #ifdef LOGERROR @@ -909,6 +532,10 @@ void vdp_test_w(unsigned int value) #endif } +/*--------------------------------------------------------------------------*/ +/* VDP Interrupts callback */ +/*--------------------------------------------------------------------------*/ + int vdp_int_ack_callback(int int_level) { /* VINT triggered ? */ @@ -929,3 +556,445 @@ int vdp_int_ack_callback(int int_level) return M68K_INT_ACK_AUTOVECTOR; } + +/*--------------------------------------------------------------------------*/ +/* FIFO emulation */ +/*--------------------------------------------------------------------------*/ +static inline void fifo_update() +{ + if (fifo_write_cnt > 0) + { + /* update FIFO reads */ + uint32 fifo_read = ((count_m68k - fifo_lastwrite) / fifo_latency); + if (fifo_read > 0) + { + fifo_write_cnt -= fifo_read; + if (fifo_write_cnt < 0) fifo_write_cnt = 0; + + /* update cycle count */ + fifo_lastwrite += fifo_read*fifo_latency; + } + } +} + +/*--------------------------------------------------------------------------*/ +/* Memory access functions */ +/*--------------------------------------------------------------------------*/ +static inline void data_w(unsigned int data) +{ + switch (code & 0x0F) + { + case 0x01: /* VRAM */ + + /* Byte-swap data if A0 is set */ + if (addr & 1) data = (data >> 8) | (data << 8); + + /* Copy SAT data to the internal SAT */ + if ((addr & sat_base_mask) == satb) + { + *(uint16 *) &sat[addr & sat_addr_mask & 0xFFFE] = data; + } + + /* Only write unique data to VRAM */ + if (data != *(uint16 *) &vram[addr & 0xFFFE]) + { + /* Write data to VRAM */ + *(uint16 *) &vram[addr & 0xFFFE] = data; + + /* Update the pattern cache */ + int name; + MARK_BG_DIRTY (addr); + } + break; + + case 0x03: /* CRAM */ + { + uint16 *p = (uint16 *) &cram[(addr & 0x7E)]; + data = PACK_CRAM (data & 0x0EEE); + if (data != *p) + { + int index = (addr >> 1) & 0x3F; + *p = data; + if (index) color_update (index, *p); + if (border == index) color_update (0x00, *p); + } + break; + } + + case 0x05: /* VSRAM */ + *(uint16 *) &vsram[(addr & 0x7E)] = data; + break; + } + + /* Increment address register */ + addr += reg[15]; +} + +/* + The reg[] array is updated at the *end* of this function, so the new + register data can be compared with the previous data. +*/ +static inline void reg_w(unsigned int r, unsigned int d) +{ + /* See if Mode 4 (SMS mode) is enabled + According to official doc, VDP registers #11 to #23 can not be written unless bit2 in register #1 is set + Fix Captain Planet & Avengers (Alt version), Bass Master Classic Pro Edition (they incidentally activate Mode 4) + */ + if (!(reg[1] & 4) && (r > 10)) return; + + switch(r) + { + case 0: /* CTRL #1 */ + + /* Line Interrupt */ + if (((d&0x10) != (reg[0]&0x10)) && hint_pending) + { + /* update IRQ status */ + irq_status &= 0x20; + irq_status |= 0x10; + if (vint_pending && (reg[1] & 0x20)) irq_status |= 6; + else if (d & 0x10) irq_status |= 4; + } + + /* Palette bit */ + if ((d&0x04) != (reg[0]&0x04)) + { + /* Update colors */ + reg[0] = d; + int i; + color_update (0x00, *(uint16 *) & cram[border << 1]); + for (i = 1; i < 0x40; i += 1) + { + color_update (i, *(uint16 *) & cram[i << 1]); + } + } + break; + + case 1: /* CTRL #2 */ + + /* Frame Interrupt */ + if (((d&0x20) != (reg[1]&0x20)) && vint_pending) + { + /* update IRQ status */ + irq_status &= 0x20; + irq_status |= 0x110; + if (d & 0x20) irq_status |= 6; + else if (hint_pending && (reg[0] & 0x10)) irq_status |= 4; + } + + /* See if the viewport height has actually been changed */ + if ((d & 8) != (reg[1] & 8)) + { + /* update the height of the viewport */ + bitmap.viewport.changed |= 1; + bitmap.viewport.h = (d & 8) ? 240 : 224; + + /* update overscan height */ + if (config.overscan) bitmap.viewport.y = ((vdp_pal ? 288 : 240) - bitmap.viewport.h) / 2; + + /* update VC table */ + if (vdp_pal) vctab = (d & 8) ? vc_pal_240 : vc_pal_224; + } + + /* Display activated/blanked during Horizontal Blanking */ + if (((d&0x40) != (reg[1]&0x40)) && (v_counter < bitmap.viewport.h)) + { + if (count_m68k <= (hint_m68k + 120)) + { + /* Redraw the current line : + - Legend of Galahad, Lemmings 2, Nigel Mansell's World Championship Racing (set display OFF) + - Deadly Moves aka Power Athlete (set display ON) + */ + reg[1] = d; + render_line(v_counter, 0); + } + } + break; + + case 2: /* NTAB */ + ntab = (d << 10) & 0xE000; + break; + + case 3: /* NTWB */ + ntwb = (d << 10) & 0xF800; + if(reg[12] & 1) ntwb &= 0xF000; + break; + + case 4: /* NTBB */ + ntbb = (d << 13) & 0xE000; + break; + + case 5: /* SATB */ + if (reg[12] & 1) + { + sat_base_mask = 0xFC00; + sat_addr_mask = 0x03FF; + } + else + { + sat_base_mask = 0xFE00; + sat_addr_mask = 0x01FF; + } + satb = (d << 9) & sat_base_mask; + break; + + case 7: + /* See if the border color has actually changed */ + d &= 0x3F; + if (d != border) + { + /* Mark the border color as modified */ + border = d; + color_update(0x00, *(uint16 *)&cram[(border << 1)]); + + /* background color modified during Horizontal Blanking */ + if ((v_counter < bitmap.viewport.h) && (count_m68k <= (line_m68k + 84))) + { + /* remap current line (see Road Rash I,II,III) */ + reg[7] = d; + remap_buffer(v_counter,bitmap.viewport.w + 2*bitmap.viewport.x); + } + } + break; + + case 12: + /* See if the viewport width has actually been changed */ + if ((d & 1) != (reg[12] & 1)) + { + if (d & 1) + { + /* Update display-dependant registers */ + ntwb = (reg[3] << 10) & 0xF000; + sat_base_mask = 0xFC00; + sat_addr_mask = 0x03FF; + satb = (reg[5] << 9) & sat_base_mask; + + /* update HC table */ + hctab = cycle2hc40; + +#ifndef NGC + /* Update viewport width */ + bitmap.viewport.w = 320; +#endif + } + else + { + /* Update display-dependant registers */ + ntwb = (reg[3] << 10) & 0xF800; + sat_base_mask = 0xFE00; + sat_addr_mask = 0x01FF; + satb = (reg[5] << 9) & sat_base_mask; + + /* update HC table */ + hctab = cycle2hc32; + +#ifndef NGC + /* Update viewport width */ + bitmap.viewport.w = 256; +#endif + } + +#ifndef NGC + /* Update viewport */ + bitmap.viewport.changed = 1; + + /* Update clipping */ + window_clip(); +#else + /* Postpound update on next frame */ + bitmap.viewport.changed = 2; +#endif + } + + /* See if the S/TE mode bit has changed */ + if ((d & 8) != (reg[12] & 8)) + { + int i; + + /* The following color update check this value */ + reg[12] = d; + + /* Update colors */ + color_update (0x00, *(uint16 *) & cram[border << 1]); + for (i = 1; i < 0x40; i += 1) + { + color_update (i, *(uint16 *) & cram[i << 1]); + } + } + break; + + case 13: /* HSCB */ + hscb = (d << 10) & 0xFC00; + break; + + case 16: /* Playfield size */ + playfield_shift = shift_table[(d & 3)]; + playfield_col_mask = col_mask_table[(d & 3)]; + playfield_row_mask = row_mask_table[(d >> 4) & 3]; + y_mask = y_mask_table[(d & 3)]; + break; + + case 17: /* update clipping */ + window_clip(); + break; + } + + /* Write new register value */ + reg[r] = d; +} + +/*--------------------------------------------------------------------------*/ +/* DMA Operations */ +/*--------------------------------------------------------------------------*/ + +/* DMA Copy + Read byte from VRAM (source), write to VRAM (addr), + bump source and add r15 to addr. + + - see how source addr is affected + (can it make high source byte inc?) +*/ +static inline void dma_copy(void) +{ + int name; + int length = (reg[20] << 8 | reg[19]) & 0xFFFF; + int source = (reg[22] << 8 | reg[21]) & 0xFFFF; + if (!length) length = 0x10000; + + dma_type = 3; + dma_length = length; + vdp_update_dma(); + + /* proceed DMA */ + do + { + vram[addr] = vram[source]; + MARK_BG_DIRTY(addr); + source = (source + 1) & 0xFFFF; + addr += reg[15]; + } while (--length); + + /* update length & source address registers */ + reg[19] = length & 0xFF; + reg[20] = (length >> 8) & 0xFF; + reg[21] = source & 0xFF; /* not sure */ + reg[22] = (source >> 8) & 0xFF; +} + +/* 68K Copy to VRAM, VSRAM or CRAM */ +static inline void dma_vbus (void) +{ + uint32 base, source = ((reg[23] & 0x7F) << 17 | reg[22] << 9 | reg[21] << 1) & 0xFFFFFE; + uint32 length = (reg[20] << 8 | reg[19]) & 0xFFFF; + uint32 temp; + + if (!length) length = 0x10000; + base = source; + + /* DMA timings */ + dma_type = (code & 0x06) ? 1 : 0; + dma_length = length; + vdp_update_dma(); + + /* DMA source */ + if ((source >> 17) == 0x50) + { + /* Z80 & I/O area */ + do + { + /* Return $FFFF only when the Z80 isn't hogging the Z-bus. + (e.g. Z80 isn't reset and 68000 has the bus) */ + if (source <= 0xa0ffff) temp = (zbusack ? *(uint16 *)(work_ram + (source & 0xffff)) : 0xffff); + + /* The I/O chip and work RAM try to drive the data bus which results + in both values being combined in random ways when read. + We return the I/O chip values which seem to have precedence, */ + else if (source <= 0xa1001f) + { + temp = io_read((source >> 1) & 0x0f); + temp = (temp << 8 | temp); + } + + /* All remaining locations access work RAM */ + else temp = *(uint16 *)(work_ram + (source & 0xffff)); + + source += 2; + source = ((base & 0xFE0000) | (source & 0x1FFFF)); + data_w(temp); + } + while (--length); + } + else + { + /* SVP latency */ + if (svp && (source < 0x400000)) + { + source = (source - 2); + } + + /* ROM & RAM */ + do + { + temp = *(uint16 *)(m68k_memory_map[source>>16].base + (source & 0xffff)); + source += 2; + source = ((base & 0xFE0000) | (source & 0x1FFFF)); + data_w(temp); + } + while (--length); + } + + /* update length & source address registers */ + reg[19] = length & 0xFF; + reg[20] = (length >> 8) & 0xFF; + reg[21] = (source >> 1) & 0xFF; + reg[22] = (source >> 9) & 0xFF; + reg[23] = (reg[23] & 0x80) | ((source >> 17) & 0x7F); +} + +/* VRAM FILL */ +static inline void dma_fill(unsigned int data) +{ + int name; + int length = (reg[20] << 8 | reg[19]) & 0xFFFF; + if (!length) length = 0x10000; + + /* DMA timings */ + dma_type = 2; + dma_length = length; + vdp_update_dma(); + + /* proceed DMA */ + data_w(data); + + /* write MSB */ + data = (data >> 8) & 0xff; + + /* detect internal SAT modification */ + if ((addr & sat_base_mask) == satb) + { + do + { + /* update internal SAT (fix Battletech) */ + WRITE_BYTE(sat, (addr & sat_addr_mask)^1, data); + WRITE_BYTE(vram, addr^1, data); + MARK_BG_DIRTY (addr); + addr += reg[15]; + } + while (--length); + } + else + { + do + { + WRITE_BYTE(vram, addr^1, data); + MARK_BG_DIRTY (addr); + addr += reg[15]; + } + while (--length); + } + + /* update length register */ + reg[19] = length & 0xFF; + reg[20] = (length >> 8) & 0xFF; + dmafill = 0; +} diff --git a/source/vdp.h b/source/vdp.h index 350fcef..9d1af5a 100644 --- a/source/vdp.h +++ b/source/vdp.h @@ -81,13 +81,13 @@ extern void vdp_init(void); extern void vdp_reset(void); extern void vdp_shutdown(void); extern void vdp_restore(uint8 *vdp_regs); +extern void vdp_update_dma(); extern void vdp_ctrl_w(unsigned int data); extern unsigned int vdp_ctrl_r(void); extern void vdp_data_w(unsigned int data); extern unsigned int vdp_data_r(void); extern unsigned int vdp_hvc_r(void); -extern void dma_update(); extern void vdp_test_w(unsigned int value); - +extern int vdp_int_ack_callback(int int_level); #endif /* _VDP_H_ */