trunk/src/mame/video/snes.c
| r21559 | r21560 | |
| 130 | 130 | }; |
| 131 | 131 | |
| 132 | 132 | /***************************************** |
| 133 | | * snes_get_bgcolor() |
| 133 | * get_bgcolor() |
| 134 | 134 | * |
| 135 | 135 | * Get the proper color (direct or from cgram) |
| 136 | 136 | *****************************************/ |
| 137 | 137 | |
| 138 | | inline UINT16 snes_ppu_class::snes_get_bgcolor( UINT8 direct_colors, UINT16 palette, UINT8 color ) |
| 138 | inline UINT16 snes_ppu_class::get_bgcolor( UINT8 direct_colors, UINT16 palette, UINT8 color ) |
| 139 | 139 | { |
| 140 | 140 | UINT16 c = 0; |
| 141 | 141 | |
| r21559 | r21560 | |
| 152 | 152 | } |
| 153 | 153 | |
| 154 | 154 | /***************************************** |
| 155 | | * snes_set_scanline_pixel() |
| 155 | * set_scanline_pixel() |
| 156 | 156 | * |
| 157 | 157 | * Store pixel color, priority, layer and |
| 158 | 158 | * color math exception (for OAM) in the |
| 159 | 159 | * proper scanline |
| 160 | 160 | *****************************************/ |
| 161 | 161 | |
| 162 | | inline void snes_ppu_class::snes_set_scanline_pixel( int screen, INT16 x, UINT16 color, UINT8 priority, UINT8 layer, int blend ) |
| 162 | inline void snes_ppu_class::set_scanline_pixel( int screen, INT16 x, UINT16 color, UINT8 priority, UINT8 layer, int blend ) |
| 163 | 163 | { |
| 164 | 164 | scanlines[screen].buffer[x] = color; |
| 165 | 165 | scanlines[screen].priority[x] = priority; |
| r21559 | r21560 | |
| 178 | 178 | *************************************************************************************************/ |
| 179 | 179 | |
| 180 | 180 | /***************************************** |
| 181 | | * snes_draw_bgtile_lores() |
| 182 | | * snes_draw_bgtile_hires() |
| 183 | | * snes_draw_oamtile_() |
| 181 | * draw_bgtile_lores() |
| 182 | * draw_bgtile_hires() |
| 183 | * draw_oamtile_() |
| 184 | 184 | * |
| 185 | 185 | * Check if a pixel is clipped or not, and |
| 186 | 186 | * copy it to the scanline buffer when |
| r21559 | r21560 | |
| 190 | 190 | * or lores) |
| 191 | 191 | *****************************************/ |
| 192 | 192 | |
| 193 | | inline void snes_ppu_class::snes_draw_bgtile_lores( UINT8 layer, INT16 ii, UINT8 colour, UINT16 pal, UINT8 direct_colors, UINT8 priority ) |
| 193 | inline void snes_ppu_class::draw_bgtile_lores( UINT8 layer, INT16 ii, UINT8 colour, UINT16 pal, UINT8 direct_colors, UINT8 priority ) |
| 194 | 194 | { |
| 195 | 195 | int screen; |
| 196 | 196 | UINT16 c; |
| r21559 | r21560 | |
| 216 | 216 | /* Only draw if we have a colour (0 == transparent) */ |
| 217 | 217 | if (clr) |
| 218 | 218 | { |
| 219 | | c = snes_get_bgcolor(direct_colors, pal, clr); |
| 220 | | snes_set_scanline_pixel(screen, ii, c, priority, layer, 0); |
| 219 | c = get_bgcolor(direct_colors, pal, clr); |
| 220 | set_scanline_pixel(screen, ii, c, priority, layer, 0); |
| 221 | 221 | } |
| 222 | 222 | } |
| 223 | 223 | } |
| 224 | 224 | } |
| 225 | 225 | } |
| 226 | 226 | |
| 227 | | inline void snes_ppu_class::snes_draw_bgtile_hires( UINT8 layer, INT16 ii, UINT8 colour, UINT16 pal, UINT8 direct_colors, UINT8 priority ) |
| 227 | inline void snes_ppu_class::draw_bgtile_hires( UINT8 layer, INT16 ii, UINT8 colour, UINT16 pal, UINT8 direct_colors, UINT8 priority ) |
| 228 | 228 | { |
| 229 | 229 | int screen; |
| 230 | 230 | UINT16 c; |
| r21559 | r21560 | |
| 251 | 251 | /* Only draw if we have a colour (0 == transparent) */ |
| 252 | 252 | if (clr) |
| 253 | 253 | { |
| 254 | | c = snes_get_bgcolor(direct_colors, pal, clr); |
| 255 | | snes_set_scanline_pixel(screen, ii >> 1, c, priority, layer, 0); |
| 254 | c = get_bgcolor(direct_colors, pal, clr); |
| 255 | set_scanline_pixel(screen, ii >> 1, c, priority, layer, 0); |
| 256 | 256 | } |
| 257 | 257 | } |
| 258 | 258 | } |
| 259 | 259 | } |
| 260 | 260 | } |
| 261 | 261 | |
| 262 | | inline void snes_ppu_class::snes_draw_oamtile( INT16 ii, UINT8 colour, UINT16 pal, UINT8 priority ) |
| 262 | inline void snes_ppu_class::draw_oamtile( INT16 ii, UINT8 colour, UINT16 pal, UINT8 priority ) |
| 263 | 263 | { |
| 264 | 264 | int screen; |
| 265 | 265 | int blend; |
| r21559 | r21560 | |
| 287 | 287 | { |
| 288 | 288 | c = m_cgram[(pal + clr) % FIXED_COLOUR]; |
| 289 | 289 | blend = (pal + clr < 192) ? 1 : 0; |
| 290 | | snes_set_scanline_pixel(screen, pos, c, priority, SNES_OAM, blend); |
| 290 | set_scanline_pixel(screen, pos, c, priority, SNES_OAM, blend); |
| 291 | 291 | } |
| 292 | 292 | } |
| 293 | 293 | } |
| 294 | 294 | } |
| 295 | 295 | |
| 296 | 296 | /***************************************** |
| 297 | | * snes_draw_tile() |
| 297 | * draw_tile() |
| 298 | 298 | * |
| 299 | 299 | * Draw 8 pixels from the expected tile |
| 300 | 300 | * by reading the color planes from vram |
| r21559 | r21560 | |
| 302 | 302 | * (depending on layer and resolution) |
| 303 | 303 | *****************************************/ |
| 304 | 304 | |
| 305 | | inline void snes_ppu_class::snes_draw_tile( UINT8 planes, UINT8 layer, UINT32 tileaddr, INT16 x, UINT8 priority, UINT8 flip, UINT8 direct_colors, UINT16 pal, UINT8 hires ) |
| 305 | inline void snes_ppu_class::draw_tile( UINT8 planes, UINT8 layer, UINT32 tileaddr, INT16 x, UINT8 priority, UINT8 flip, UINT8 direct_colors, UINT16 pal, UINT8 hires ) |
| 306 | 306 | { |
| 307 | 307 | UINT8 plane[8]; |
| 308 | 308 | INT16 ii, jj; |
| r21559 | r21560 | |
| 336 | 336 | } |
| 337 | 337 | |
| 338 | 338 | if (layer == SNES_OAM) |
| 339 | | snes_draw_oamtile(ii, colour, pal, priority); |
| 339 | draw_oamtile(ii, colour, pal, priority); |
| 340 | 340 | else if (!hires) |
| 341 | 341 | { |
| 342 | 342 | if (mosaic) |
| 343 | 343 | { |
| 344 | 344 | for (x_mos = 0; x_mos < (m_mosaic_size + 1); x_mos++) |
| 345 | | snes_draw_bgtile_lores(layer, ii + x_mos, colour, pal, direct_colors, priority); |
| 345 | draw_bgtile_lores(layer, ii + x_mos, colour, pal, direct_colors, priority); |
| 346 | 346 | ii += x_mos - 1; |
| 347 | 347 | } |
| 348 | 348 | else |
| 349 | | snes_draw_bgtile_lores(layer, ii, colour, pal, direct_colors, priority); |
| 349 | draw_bgtile_lores(layer, ii, colour, pal, direct_colors, priority); |
| 350 | 350 | } |
| 351 | 351 | else /* hires */ |
| 352 | 352 | { |
| 353 | 353 | if (mosaic) |
| 354 | 354 | { |
| 355 | 355 | for (x_mos = 0; x_mos < (m_mosaic_size + 1); x_mos++) |
| 356 | | snes_draw_bgtile_hires(layer, ii + x_mos, colour, pal, direct_colors, priority); |
| 356 | draw_bgtile_hires(layer, ii + x_mos, colour, pal, direct_colors, priority); |
| 357 | 357 | ii += x_mos - 1; |
| 358 | 358 | } |
| 359 | 359 | else |
| 360 | | snes_draw_bgtile_hires(layer, ii, colour, pal, direct_colors, priority); |
| 360 | draw_bgtile_hires(layer, ii, colour, pal, direct_colors, priority); |
| 361 | 361 | } |
| 362 | 362 | } |
| 363 | 363 | } |
| r21559 | r21560 | |
| 368 | 368 | * BG drawing theory of each scanline is quite easy: depending on the graphics Mode (0-7), there |
| 369 | 369 | * are up to 4 background layers. Pixels for each BG layer can have two different priorities. |
| 370 | 370 | * Depending on the line and on the BGHOFS and BGVOFS PPU registers, we first determine the tile |
| 371 | | * address in m_vram (by determining x,y coord and tile size and by calling snes_get_tmap_addr). |
| 371 | * address in m_vram (by determining x,y coord and tile size and by calling get_tmap_addr). |
| 372 | 372 | * Then, we load the correspondent data and we determine the tile properties: which priority to |
| 373 | 373 | * use, which palette etc. Finally, for each pixel of the tile appearing on screen, we check if |
| 374 | 374 | * the tile priority is higher than the BG/OAM already stored in that pixel for that line. If so |
| r21559 | r21560 | |
| 380 | 380 | *************************************************************************************************/ |
| 381 | 381 | |
| 382 | 382 | /********************************************* |
| 383 | | * snes_get_tmap_addr() |
| 383 | * get_tmap_addr() |
| 384 | 384 | * |
| 385 | 385 | * Find the address in VRAM of the tile (x,y) |
| 386 | 386 | *********************************************/ |
| 387 | 387 | |
| 388 | | inline UINT32 snes_ppu_class::snes_get_tmap_addr( UINT8 layer, UINT8 tile_size, UINT32 base, UINT32 x, UINT32 y ) |
| 388 | inline UINT32 snes_ppu_class::get_tmap_addr( UINT8 layer, UINT8 tile_size, UINT32 base, UINT32 x, UINT32 y ) |
| 389 | 389 | { |
| 390 | 390 | UINT32 res = base; |
| 391 | 391 | x >>= (3 + tile_size); |
| r21559 | r21560 | |
| 403 | 403 | } |
| 404 | 404 | |
| 405 | 405 | /********************************************* |
| 406 | | * snes_update_line() |
| 406 | * update_line() |
| 407 | 407 | * |
| 408 | 408 | * Update an entire line of tiles. |
| 409 | 409 | *********************************************/ |
| 410 | 410 | |
| 411 | | inline void snes_ppu_class::snes_update_line( UINT16 curline, UINT8 layer, UINT8 priority_b, UINT8 priority_a, UINT8 color_depth, UINT8 hires, UINT8 offset_per_tile, UINT8 direct_colors ) |
| 411 | inline void snes_ppu_class::update_line( UINT16 curline, UINT8 layer, UINT8 priority_b, UINT8 priority_a, UINT8 color_depth, UINT8 hires, UINT8 offset_per_tile, UINT8 direct_colors ) |
| 412 | 412 | { |
| 413 | 413 | UINT32 tmap, tile, xoff, yoff, charaddr, addr; |
| 414 | 414 | UINT16 ii = 0, vflip, hflip, pal, pal_direct, tilemap; |
| r21559 | r21560 | |
| 473 | 473 | { |
| 474 | 474 | case SNES_OPT_MODE2: |
| 475 | 475 | case SNES_OPT_MODE6: |
| 476 | | haddr = snes_get_tmap_addr(SNES_BG3, m_layer[SNES_BG3].tile_size, m_layer[SNES_BG3].tilemap << 9, (opt_x - 8) + ((m_layer[SNES_BG3].hoffs & 0x3ff) & ~7), (m_layer[SNES_BG3].voffs & 0x3ff)); |
| 477 | | vaddr = snes_get_tmap_addr(SNES_BG3, m_layer[SNES_BG3].tile_size, m_layer[SNES_BG3].tilemap << 9, (opt_x - 8) + ((m_layer[SNES_BG3].hoffs & 0x3ff) & ~7), (m_layer[SNES_BG3].voffs & 0x3ff) + 8); |
| 476 | haddr = get_tmap_addr(SNES_BG3, m_layer[SNES_BG3].tile_size, m_layer[SNES_BG3].tilemap << 9, (opt_x - 8) + ((m_layer[SNES_BG3].hoffs & 0x3ff) & ~7), (m_layer[SNES_BG3].voffs & 0x3ff)); |
| 477 | vaddr = get_tmap_addr(SNES_BG3, m_layer[SNES_BG3].tile_size, m_layer[SNES_BG3].tilemap << 9, (opt_x - 8) + ((m_layer[SNES_BG3].hoffs & 0x3ff) & ~7), (m_layer[SNES_BG3].voffs & 0x3ff) + 8); |
| 478 | 478 | hval = m_vram[haddr % SNES_VRAM_SIZE] | (m_vram[(haddr + 1) % SNES_VRAM_SIZE] << 8); |
| 479 | 479 | vval = m_vram[vaddr % SNES_VRAM_SIZE] | (m_vram[(vaddr + 1) % SNES_VRAM_SIZE] << 8); |
| 480 | 480 | if (BIT(hval, opt_bit)) |
| r21559 | r21560 | |
| 483 | 483 | ypos = curline + vval; |
| 484 | 484 | break; |
| 485 | 485 | case SNES_OPT_MODE4: |
| 486 | | haddr = snes_get_tmap_addr(SNES_BG3, m_layer[SNES_BG3].tile_size, m_layer[SNES_BG3].tilemap << 9, (opt_x - 8) + ((m_layer[SNES_BG3].hoffs & 0x3ff) & ~7), (m_layer[SNES_BG3].voffs & 0x3ff)); |
| 486 | haddr = get_tmap_addr(SNES_BG3, m_layer[SNES_BG3].tile_size, m_layer[SNES_BG3].tilemap << 9, (opt_x - 8) + ((m_layer[SNES_BG3].hoffs & 0x3ff) & ~7), (m_layer[SNES_BG3].voffs & 0x3ff)); |
| 487 | 487 | hval = m_vram[haddr % SNES_VRAM_SIZE] | (m_vram[(haddr + 1) % SNES_VRAM_SIZE] << 8); |
| 488 | 488 | if (BIT(hval, opt_bit)) |
| 489 | 489 | { |
| r21559 | r21560 | |
| 497 | 497 | } |
| 498 | 498 | } |
| 499 | 499 | |
| 500 | | addr = snes_get_tmap_addr(layer, tile_size, tmap, xpos, ypos); |
| 500 | addr = get_tmap_addr(layer, tile_size, tmap, xpos, ypos); |
| 501 | 501 | |
| 502 | 502 | /* |
| 503 | 503 | Tilemap format |
| r21559 | r21560 | |
| 566 | 566 | if (hires) |
| 567 | 567 | { |
| 568 | 568 | /* draw 16 pixels (the routine will automatically send half of them to the mainscreen scanline and half to the subscreen one) */ |
| 569 | | snes_draw_tile(color_planes, layer, charaddr + (((tile + 0) & 0x3ff) * 8 * color_planes) + yscroll, (ii - xscroll) * 2, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires); |
| 570 | | snes_draw_tile(color_planes, layer, charaddr + (((tile + tile_incr) & 0x3ff) * 8 * color_planes) + yscroll, (ii - xscroll) * 2 + 8, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires); |
| 569 | draw_tile(color_planes, layer, charaddr + (((tile + 0) & 0x3ff) * 8 * color_planes) + yscroll, (ii - xscroll) * 2, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires); |
| 570 | draw_tile(color_planes, layer, charaddr + (((tile + tile_incr) & 0x3ff) * 8 * color_planes) + yscroll, (ii - xscroll) * 2 + 8, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires); |
| 571 | 571 | ii += 8; |
| 572 | 572 | } |
| 573 | 573 | else |
| 574 | 574 | { |
| 575 | | snes_draw_tile(color_planes, layer, charaddr + ((tile & 0x3ff) * 8 * color_planes) + yscroll, ii - xscroll, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires); |
| 575 | draw_tile(color_planes, layer, charaddr + ((tile & 0x3ff) * 8 * color_planes) + yscroll, ii - xscroll, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires); |
| 576 | 576 | ii += 8; |
| 577 | 577 | |
| 578 | 578 | if (tile_size) |
| 579 | 579 | { |
| 580 | | snes_draw_tile(color_planes, layer, charaddr + (((tile + tile_incr) & 0x3ff) * 8 * color_planes) + yscroll, ii - xscroll, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires); |
| 580 | draw_tile(color_planes, layer, charaddr + (((tile + tile_incr) & 0x3ff) * 8 * color_planes) + yscroll, ii - xscroll, priority, hflip, direct_colors, direct_colors ? pal_direct : pal, hires); |
| 581 | 581 | ii += 8; |
| 582 | 582 | } |
| 583 | 583 | } |
| r21559 | r21560 | |
| 586 | 586 | |
| 587 | 587 | |
| 588 | 588 | /********************************************* |
| 589 | | * snes_update_line_mode7() |
| 589 | * update_line_mode7() |
| 590 | 590 | * |
| 591 | 591 | * Update an entire line of mode7 tiles. |
| 592 | 592 | *********************************************/ |
| 593 | 593 | |
| 594 | 594 | #define MODE7_CLIP(x) (((x) & 0x2000) ? ((x) | ~0x03ff) : ((x) & 0x03ff)) |
| 595 | 595 | |
| 596 | | void snes_ppu_class::snes_update_line_mode7( UINT16 curline, UINT8 layer, UINT8 priority_b, UINT8 priority_a ) |
| 596 | void snes_ppu_class::update_line_mode7( UINT16 curline, UINT8 layer, UINT8 priority_b, UINT8 priority_a ) |
| 597 | 597 | { |
| 598 | 598 | UINT32 tiled; |
| 599 | 599 | INT16 ma, mb, mc, md; |
| r21559 | r21560 | |
| 748 | 748 | /* Direct select, but only outside EXTBG! */ |
| 749 | 749 | // Direct color format is: 0 | BB000 | GGG00 | RRR00, HW confirms that the data is zero padded. |
| 750 | 750 | // In other words, like normal direct color, with pal = 0 |
| 751 | | c = snes_get_bgcolor(m_direct_color && layer == SNES_BG1, 0, clr); |
| 752 | | snes_set_scanline_pixel(screen, xpos, c, priority, layer, 0); |
| 751 | c = get_bgcolor(m_direct_color && layer == SNES_BG1, 0, clr); |
| 752 | set_scanline_pixel(screen, xpos, c, priority, layer, 0); |
| 753 | 753 | } |
| 754 | 754 | } |
| 755 | 755 | } |
| r21559 | r21560 | |
| 761 | 761 | * |
| 762 | 762 | * 1. First of all: sprites are drawn one line in advance. We emulate this by caching the |
| 763 | 763 | * starting vram address, the sprite size and the "name select" at each line, and by using |
| 764 | | * them the next line to output the proper sprites - see snes_update_obsel. |
| 764 | * them the next line to output the proper sprites - see update_obsel. |
| 765 | 765 | * |
| 766 | 766 | * 2. Each line can select its sprites among 128 available ones in oam_ram, hence we start |
| 767 | 767 | * by creating a list of the available objects (each one with its x,y coordinate, its size, |
| 768 | | * its tile address, etc.) - see snes_oam_list_build. |
| 768 | * its tile address, etc.) - see oam_list_build. |
| 769 | 769 | * |
| 770 | 770 | * 3. Next, we start finding out which sprites will appear in the line: starting from |
| 771 | 771 | * FirstSprite, we count 32 OBJs which intersect our line and we store their indexes in the |
| r21559 | r21560 | |
| 778 | 778 | * item which intersects the scanline), towards oam_itemlist[0], i.e. the higher tiles (say |
| 779 | 779 | * oam_tilelist[34], or the last tile which appear on screen) will contain FirstSprite object, |
| 780 | 780 | * or the sprites with closer index to FirstSprite which get displayed. This will play an |
| 781 | | * important role for sprite priority - see snes_update_objects_rto. |
| 781 | * important role for sprite priority - see update_objects_rto. |
| 782 | 782 | * |
| 783 | 783 | * 4. All the above happens at the beginning of each VIDEO_UPDATE. When we finally draw the |
| 784 | 784 | * scanline, we pass through the oam_tilelist and we store the displayed pixels in our scanline |
| r21559 | r21560 | |
| 789 | 789 | * priorities are (differently from what we did with BGs): in the end, we will have in each pixel z |
| 790 | 790 | * its topmost sprite and scanline.priority[z] will be the topmost sprite priority as expected. |
| 791 | 791 | * Of course, sprite drawing must happen before BG drawing, so that afterwords BG pixels properly |
| 792 | | * test their priority with the one of the correct sprite - see snes_update_objects. |
| 792 | * test their priority with the one of the correct sprite - see update_objects. |
| 793 | 793 | *************************************************************************************************/ |
| 794 | 794 | |
| 795 | 795 | struct OAM |
| r21559 | r21560 | |
| 813 | 813 | static struct TILELIST oam_tilelist[34]; |
| 814 | 814 | |
| 815 | 815 | /********************************************* |
| 816 | | * snes_update_obsel() |
| 816 | * update_obsel() |
| 817 | 817 | * |
| 818 | 818 | * Update sprite settings for next line. |
| 819 | 819 | *********************************************/ |
| 820 | 820 | |
| 821 | | void snes_ppu_class::snes_update_obsel( void ) |
| 821 | void snes_ppu_class::update_obsel( void ) |
| 822 | 822 | { |
| 823 | 823 | m_layer[SNES_OAM].charmap = m_oam.next_charmap; |
| 824 | 824 | m_oam.name_select = m_oam.next_name_select; |
| r21559 | r21560 | |
| 831 | 831 | } |
| 832 | 832 | |
| 833 | 833 | /********************************************* |
| 834 | | * snes_oam_list_build() |
| 834 | * oam_list_build() |
| 835 | 835 | * |
| 836 | 836 | * Build a list of the available obj in OAM ram. |
| 837 | 837 | *********************************************/ |
| 838 | 838 | |
| 839 | | void snes_ppu_class::snes_oam_list_build( void ) |
| 839 | void snes_ppu_class::oam_list_build( void ) |
| 840 | 840 | { |
| 841 | 841 | UINT8 *oamram = (UINT8 *)m_oam_ram; |
| 842 | 842 | INT16 oam = 0x1ff; |
| r21559 | r21560 | |
| 942 | 942 | } |
| 943 | 943 | |
| 944 | 944 | /********************************************* |
| 945 | | * snes_update_objects_rto() |
| 945 | * update_objects_rto() |
| 946 | 946 | * |
| 947 | 947 | * Determine which OBJs will be drawn on this |
| 948 | 948 | * scanline. |
| 949 | 949 | *********************************************/ |
| 950 | 950 | |
| 951 | | void snes_ppu_class::snes_update_objects_rto( UINT16 curline ) |
| 951 | void snes_ppu_class::update_objects_rto( UINT16 curline ) |
| 952 | 952 | { |
| 953 | 953 | int ii, jj, active_sprite; |
| 954 | 954 | UINT8 range_over, time_over; |
| r21559 | r21560 | |
| 959 | 959 | INT16 x, y; |
| 960 | 960 | UINT32 name_sel = 0; |
| 961 | 961 | |
| 962 | | snes_oam_list_build(); |
| 962 | oam_list_build(); |
| 963 | 963 | |
| 964 | 964 | /* initialize counters */ |
| 965 | 965 | range_over = 0; |
| r21559 | r21560 | |
| 1057 | 1057 | } |
| 1058 | 1058 | |
| 1059 | 1059 | /********************************************* |
| 1060 | | * snes_update_objects() |
| 1060 | * update_objects() |
| 1061 | 1061 | * |
| 1062 | 1062 | * Update an entire line of sprites. |
| 1063 | 1063 | *********************************************/ |
| 1064 | 1064 | |
| 1065 | | void snes_ppu_class::snes_update_objects( UINT8 priority_oam0, UINT8 priority_oam1, UINT8 priority_oam2, UINT8 priority_oam3 ) |
| 1065 | void snes_ppu_class::update_objects( UINT8 priority_oam0, UINT8 priority_oam1, UINT8 priority_oam2, UINT8 priority_oam3 ) |
| 1066 | 1066 | { |
| 1067 | 1067 | UINT8 pri, priority[4]; |
| 1068 | 1068 | UINT32 charaddr; |
| r21559 | r21560 | |
| 1112 | 1112 | #endif /* SNES_LAYER_DEBUG */ |
| 1113 | 1113 | |
| 1114 | 1114 | /* OAM tiles have fixed planes (4), no direct color and no hires, but otherwise work the same as BG ones */ |
| 1115 | | snes_draw_tile(4, SNES_OAM, charaddr + oam_tilelist[tile].tileaddr, oam_tilelist[tile].x, pri, oam_tilelist[tile].hflip, 0, oam_tilelist[tile].pal, 0); |
| 1115 | draw_tile(4, SNES_OAM, charaddr + oam_tilelist[tile].tileaddr, oam_tilelist[tile].x, pri, oam_tilelist[tile].hflip, 0, oam_tilelist[tile].pal, 0); |
| 1116 | 1116 | } |
| 1117 | 1117 | } |
| 1118 | 1118 | |
| r21559 | r21560 | |
| 1123 | 1123 | * Update Mode X line. |
| 1124 | 1124 | *********************************************/ |
| 1125 | 1125 | |
| 1126 | | void snes_ppu_class::snes_update_mode_0( UINT16 curline ) |
| 1126 | void snes_ppu_class::update_mode_0( UINT16 curline ) |
| 1127 | 1127 | { |
| 1128 | 1128 | #if SNES_LAYER_DEBUG |
| 1129 | 1129 | if (debug_options.mode_disabled[0]) |
| 1130 | 1130 | return; |
| 1131 | 1131 | #endif /* SNES_LAYER_DEBUG */ |
| 1132 | 1132 | |
| 1133 | | snes_update_objects(3, 6, 9, 12); |
| 1134 | | snes_update_line(curline, SNES_BG1, 8, 11, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); |
| 1135 | | snes_update_line(curline, SNES_BG2, 7, 10, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); |
| 1136 | | snes_update_line(curline, SNES_BG3, 2, 5, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); |
| 1137 | | snes_update_line(curline, SNES_BG4, 1, 4, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); |
| 1133 | update_objects(3, 6, 9, 12); |
| 1134 | update_line(curline, SNES_BG1, 8, 11, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); |
| 1135 | update_line(curline, SNES_BG2, 7, 10, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); |
| 1136 | update_line(curline, SNES_BG3, 2, 5, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); |
| 1137 | update_line(curline, SNES_BG4, 1, 4, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); |
| 1138 | 1138 | } |
| 1139 | 1139 | |
| 1140 | | void snes_ppu_class::snes_update_mode_1( UINT16 curline ) |
| 1140 | void snes_ppu_class::update_mode_1( UINT16 curline ) |
| 1141 | 1141 | { |
| 1142 | 1142 | #if SNES_LAYER_DEBUG |
| 1143 | 1143 | if (debug_options.mode_disabled[1]) |
| r21559 | r21560 | |
| 1146 | 1146 | |
| 1147 | 1147 | if (!m_bg3_priority_bit) |
| 1148 | 1148 | { |
| 1149 | | snes_update_objects(2, 4, 7, 10); |
| 1150 | | snes_update_line(curline, SNES_BG1, 6, 9, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); |
| 1151 | | snes_update_line(curline, SNES_BG2, 5, 8, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); |
| 1152 | | snes_update_line(curline, SNES_BG3, 1, 3, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); |
| 1149 | update_objects(2, 4, 7, 10); |
| 1150 | update_line(curline, SNES_BG1, 6, 9, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); |
| 1151 | update_line(curline, SNES_BG2, 5, 8, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); |
| 1152 | update_line(curline, SNES_BG3, 1, 3, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); |
| 1153 | 1153 | } |
| 1154 | 1154 | else |
| 1155 | 1155 | { |
| 1156 | | snes_update_objects(2, 3, 6, 9); |
| 1157 | | snes_update_line(curline, SNES_BG1, 5, 8, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); |
| 1158 | | snes_update_line(curline, SNES_BG2, 4, 7, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); |
| 1159 | | snes_update_line(curline, SNES_BG3, 1, 10, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); |
| 1156 | update_objects(2, 3, 6, 9); |
| 1157 | update_line(curline, SNES_BG1, 5, 8, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); |
| 1158 | update_line(curline, SNES_BG2, 4, 7, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); |
| 1159 | update_line(curline, SNES_BG3, 1, 10, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_NONE, 0); |
| 1160 | 1160 | } |
| 1161 | 1161 | } |
| 1162 | 1162 | |
| 1163 | | void snes_ppu_class::snes_update_mode_2( UINT16 curline ) |
| 1163 | void snes_ppu_class::update_mode_2( UINT16 curline ) |
| 1164 | 1164 | { |
| 1165 | 1165 | #if SNES_LAYER_DEBUG |
| 1166 | 1166 | if (debug_options.mode_disabled[2]) |
| 1167 | 1167 | return; |
| 1168 | 1168 | #endif /* SNES_LAYER_DEBUG */ |
| 1169 | 1169 | |
| 1170 | | snes_update_objects(2, 4, 6, 8); |
| 1171 | | snes_update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_MODE2, 0); |
| 1172 | | snes_update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_MODE2, 0); |
| 1170 | update_objects(2, 4, 6, 8); |
| 1171 | update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_MODE2, 0); |
| 1172 | update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_MODE2, 0); |
| 1173 | 1173 | } |
| 1174 | 1174 | |
| 1175 | | void snes_ppu_class::snes_update_mode_3( UINT16 curline ) |
| 1175 | void snes_ppu_class::update_mode_3( UINT16 curline ) |
| 1176 | 1176 | { |
| 1177 | 1177 | #if SNES_LAYER_DEBUG |
| 1178 | 1178 | if (debug_options.mode_disabled[3]) |
| 1179 | 1179 | return; |
| 1180 | 1180 | #endif /* SNES_LAYER_DEBUG */ |
| 1181 | 1181 | |
| 1182 | | snes_update_objects(2, 4, 6, 8); |
| 1183 | | snes_update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_8BPP, 0, SNES_OPT_NONE, m_direct_color); |
| 1184 | | snes_update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); |
| 1182 | update_objects(2, 4, 6, 8); |
| 1183 | update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_8BPP, 0, SNES_OPT_NONE, m_direct_color); |
| 1184 | update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_4BPP, 0, SNES_OPT_NONE, 0); |
| 1185 | 1185 | } |
| 1186 | 1186 | |
| 1187 | | void snes_ppu_class::snes_update_mode_4( UINT16 curline ) |
| 1187 | void snes_ppu_class::update_mode_4( UINT16 curline ) |
| 1188 | 1188 | { |
| 1189 | 1189 | #if SNES_LAYER_DEBUG |
| 1190 | 1190 | if (debug_options.mode_disabled[4]) |
| 1191 | 1191 | return; |
| 1192 | 1192 | #endif /* SNES_LAYER_DEBUG */ |
| 1193 | 1193 | |
| 1194 | | snes_update_objects(2, 4, 6, 8); |
| 1195 | | snes_update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_8BPP, 0, SNES_OPT_MODE4, m_direct_color); |
| 1196 | | snes_update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_MODE4, 0); |
| 1194 | update_objects(2, 4, 6, 8); |
| 1195 | update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_8BPP, 0, SNES_OPT_MODE4, m_direct_color); |
| 1196 | update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_2BPP, 0, SNES_OPT_MODE4, 0); |
| 1197 | 1197 | } |
| 1198 | 1198 | |
| 1199 | | void snes_ppu_class::snes_update_mode_5( UINT16 curline ) |
| 1199 | void snes_ppu_class::update_mode_5( UINT16 curline ) |
| 1200 | 1200 | { |
| 1201 | 1201 | #if SNES_LAYER_DEBUG |
| 1202 | 1202 | if (debug_options.mode_disabled[5]) |
| 1203 | 1203 | return; |
| 1204 | 1204 | #endif /* SNES_LAYER_DEBUG */ |
| 1205 | 1205 | |
| 1206 | | snes_update_objects(2, 4, 6, 8); |
| 1207 | | snes_update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_4BPP, 1, SNES_OPT_NONE, 0); |
| 1208 | | snes_update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_2BPP, 1, SNES_OPT_NONE, 0); |
| 1206 | update_objects(2, 4, 6, 8); |
| 1207 | update_line(curline, SNES_BG1, 3, 7, SNES_COLOR_DEPTH_4BPP, 1, SNES_OPT_NONE, 0); |
| 1208 | update_line(curline, SNES_BG2, 1, 5, SNES_COLOR_DEPTH_2BPP, 1, SNES_OPT_NONE, 0); |
| 1209 | 1209 | } |
| 1210 | 1210 | |
| 1211 | | void snes_ppu_class::snes_update_mode_6( UINT16 curline ) |
| 1211 | void snes_ppu_class::update_mode_6( UINT16 curline ) |
| 1212 | 1212 | { |
| 1213 | 1213 | #if SNES_LAYER_DEBUG |
| 1214 | 1214 | if (debug_options.mode_disabled[6]) |
| 1215 | 1215 | return; |
| 1216 | 1216 | #endif /* SNES_LAYER_DEBUG */ |
| 1217 | 1217 | |
| 1218 | | snes_update_objects(1, 3, 4, 6); |
| 1219 | | snes_update_line(curline, SNES_BG1, 2, 5, SNES_COLOR_DEPTH_4BPP, 1, SNES_OPT_MODE6, 0); |
| 1218 | update_objects(1, 3, 4, 6); |
| 1219 | update_line(curline, SNES_BG1, 2, 5, SNES_COLOR_DEPTH_4BPP, 1, SNES_OPT_MODE6, 0); |
| 1220 | 1220 | } |
| 1221 | 1221 | |
| 1222 | | void snes_ppu_class::snes_update_mode_7( UINT16 curline ) |
| 1222 | void snes_ppu_class::update_mode_7( UINT16 curline ) |
| 1223 | 1223 | { |
| 1224 | 1224 | #if SNES_LAYER_DEBUG |
| 1225 | 1225 | if (debug_options.mode_disabled[7]) |
| r21559 | r21560 | |
| 1228 | 1228 | |
| 1229 | 1229 | if (!m_mode7.extbg) |
| 1230 | 1230 | { |
| 1231 | | snes_update_objects(1, 3, 4, 5); |
| 1232 | | snes_update_line_mode7(curline, SNES_BG1, 2, 2); |
| 1231 | update_objects(1, 3, 4, 5); |
| 1232 | update_line_mode7(curline, SNES_BG1, 2, 2); |
| 1233 | 1233 | } |
| 1234 | 1234 | else |
| 1235 | 1235 | { |
| 1236 | | snes_update_objects(2, 4, 6, 7); |
| 1237 | | snes_update_line_mode7(curline, SNES_BG1, 3, 3); |
| 1238 | | snes_update_line_mode7(curline, SNES_BG2, 1, 5); |
| 1236 | update_objects(2, 4, 6, 7); |
| 1237 | update_line_mode7(curline, SNES_BG1, 3, 3); |
| 1238 | update_line_mode7(curline, SNES_BG2, 1, 5); |
| 1239 | 1239 | } |
| 1240 | 1240 | } |
| 1241 | 1241 | |
| r21559 | r21560 | |
| 1245 | 1245 | * Draw the whole screen (Mode 0 -> 7). |
| 1246 | 1246 | *********************************************/ |
| 1247 | 1247 | |
| 1248 | | void snes_ppu_class::snes_draw_screens( UINT16 curline ) |
| 1248 | void snes_ppu_class::draw_screens( UINT16 curline ) |
| 1249 | 1249 | { |
| 1250 | 1250 | switch (m_mode) |
| 1251 | 1251 | { |
| 1252 | | case 0: snes_update_mode_0(curline); break; /* Mode 0 */ |
| 1253 | | case 1: snes_update_mode_1(curline); break; /* Mode 1 */ |
| 1254 | | case 2: snes_update_mode_2(curline); break; /* Mode 2 - Supports offset per tile */ |
| 1255 | | case 3: snes_update_mode_3(curline); break; /* Mode 3 - Supports direct colour */ |
| 1256 | | case 4: snes_update_mode_4(curline); break; /* Mode 4 - Supports offset per tile and direct colour */ |
| 1257 | | case 5: snes_update_mode_5(curline); break; /* Mode 5 - Supports hires */ |
| 1258 | | case 6: snes_update_mode_6(curline); break; /* Mode 6 - Supports offset per tile and hires */ |
| 1259 | | case 7: snes_update_mode_7(curline); break; /* Mode 7 - Supports direct colour */ |
| 1252 | case 0: update_mode_0(curline); break; /* Mode 0 */ |
| 1253 | case 1: update_mode_1(curline); break; /* Mode 1 */ |
| 1254 | case 2: update_mode_2(curline); break; /* Mode 2 - Supports offset per tile */ |
| 1255 | case 3: update_mode_3(curline); break; /* Mode 3 - Supports direct colour */ |
| 1256 | case 4: update_mode_4(curline); break; /* Mode 4 - Supports offset per tile and direct colour */ |
| 1257 | case 5: update_mode_5(curline); break; /* Mode 5 - Supports hires */ |
| 1258 | case 6: update_mode_6(curline); break; /* Mode 6 - Supports offset per tile and hires */ |
| 1259 | case 7: update_mode_7(curline); break; /* Mode 7 - Supports direct colour */ |
| 1260 | 1260 | } |
| 1261 | 1261 | } |
| 1262 | 1262 | |
| 1263 | 1263 | /********************************************* |
| 1264 | | * snes_update_windowmasks() |
| 1264 | * update_windowmasks() |
| 1265 | 1265 | * |
| 1266 | 1266 | * An example of how windows work: |
| 1267 | 1267 | * Win1: ...#####...... |
| r21559 | r21560 | |
| 1273 | 1273 | * XNOR: ###...##...### ...###..###... |
| 1274 | 1274 | *********************************************/ |
| 1275 | 1275 | |
| 1276 | | void snes_ppu_class::snes_update_windowmasks( void ) |
| 1276 | void snes_ppu_class::update_windowmasks( void ) |
| 1277 | 1277 | { |
| 1278 | 1278 | UINT16 ii, jj; |
| 1279 | 1279 | INT8 w1, w2; |
| r21559 | r21560 | |
| 1340 | 1340 | } |
| 1341 | 1341 | |
| 1342 | 1342 | /********************************************* |
| 1343 | | * snes_update_offsets() |
| 1343 | * update_offsets() |
| 1344 | 1344 | * |
| 1345 | 1345 | * Update the offsets with the latest changes. |
| 1346 | 1346 | * This is currently unused, but it could |
| 1347 | 1347 | * possibly be handy for some minor optimization |
| 1348 | 1348 | *********************************************/ |
| 1349 | 1349 | |
| 1350 | | void snes_ppu_class::snes_update_offsets( void ) |
| 1350 | void snes_ppu_class::update_offsets( void ) |
| 1351 | 1351 | { |
| 1352 | 1352 | int ii; |
| 1353 | 1353 | for (ii = 0; ii < 4; ii++) |
| r21559 | r21560 | |
| 1357 | 1357 | } |
| 1358 | 1358 | |
| 1359 | 1359 | /***************************************** |
| 1360 | | * snes_draw_blend() |
| 1360 | * draw_blend() |
| 1361 | 1361 | * |
| 1362 | 1362 | * Routine for additive/subtractive blending |
| 1363 | 1363 | * between the main and sub screens, i.e. |
| 1364 | 1364 | * color math. |
| 1365 | 1365 | *****************************************/ |
| 1366 | 1366 | |
| 1367 | | inline void snes_ppu_class::snes_draw_blend( UINT16 offset, UINT16 *colour, UINT8 prevent_color_math, UINT8 black_pen_clip, int switch_screens ) |
| 1367 | inline void snes_ppu_class::draw_blend( UINT16 offset, UINT16 *colour, UINT8 prevent_color_math, UINT8 black_pen_clip, int switch_screens ) |
| 1368 | 1368 | { |
| 1369 | 1369 | #if SNES_LAYER_DEBUG |
| 1370 | 1370 | if (debug_options.colormath_disabled) |
| r21559 | r21560 | |
| 1372 | 1372 | #endif /* SNES_LAYER_DEBUG */ |
| 1373 | 1373 | |
| 1374 | 1374 | /* when color math is applied to subscreen pixels, the blending depends on the blending used by the previous mainscreen |
| 1375 | | pixel, except for subscreen pixel 0 which has no previous mainscreen pixel, see comments in snes_refresh_scanline */ |
| 1375 | pixel, except for subscreen pixel 0 which has no previous mainscreen pixel, see comments in refresh_scanline */ |
| 1376 | 1376 | if (switch_screens && offset > 0) |
| 1377 | 1377 | offset -= 1; |
| 1378 | 1378 | |
| r21559 | r21560 | |
| 1474 | 1474 | } |
| 1475 | 1475 | |
| 1476 | 1476 | /********************************************* |
| 1477 | | * snes_refresh_scanline() |
| 1477 | * refresh_scanline() |
| 1478 | 1478 | * |
| 1479 | 1479 | * Redraw the current line. |
| 1480 | 1480 | *********************************************/ |
| r21559 | r21560 | |
| 1492 | 1492 | * the optimized averaging algorithm. |
| 1493 | 1493 | *********************************************/ |
| 1494 | 1494 | |
| 1495 | | void snes_ppu_class::snes_refresh_scanline( running_machine &machine, bitmap_rgb32 &bitmap, UINT16 curline ) |
| 1495 | void snes_ppu_class::refresh_scanline( running_machine &machine, bitmap_rgb32 &bitmap, UINT16 curline ) |
| 1496 | 1496 | { |
| 1497 | 1497 | UINT16 ii; |
| 1498 | 1498 | int x; |
| r21559 | r21560 | |
| 1511 | 1511 | { |
| 1512 | 1512 | /* Update clip window masks if necessary */ |
| 1513 | 1513 | if (m_update_windows) |
| 1514 | | snes_update_windowmasks(); |
| 1514 | update_windowmasks(); |
| 1515 | 1515 | /* Update the offsets if necessary */ |
| 1516 | 1516 | if (m_update_offsets) |
| 1517 | | snes_update_offsets(); |
| 1517 | update_offsets(); |
| 1518 | 1518 | |
| 1519 | 1519 | /* Clear priority */ |
| 1520 | 1520 | memset(scanlines[SNES_MAINSCREEN].priority, 0, SNES_SCR_WIDTH); |
| r21559 | r21560 | |
| 1540 | 1540 | } |
| 1541 | 1541 | |
| 1542 | 1542 | /* Prepare OAM for this scanline */ |
| 1543 | | snes_update_objects_rto(curline); |
| 1543 | update_objects_rto(curline); |
| 1544 | 1544 | |
| 1545 | 1545 | /* Draw scanline */ |
| 1546 | | snes_draw_screens(curline); |
| 1546 | draw_screens(curline); |
| 1547 | 1547 | |
| 1548 | | snes_update_obsel(); |
| 1548 | update_obsel(); |
| 1549 | 1549 | |
| 1550 | 1550 | #if SNES_LAYER_DEBUG |
| 1551 | | if (snes_dbg_video(machine, curline, snes_ram)) |
| 1551 | if (dbg_video(machine, curline, snes_ram)) |
| 1552 | 1552 | { |
| 1553 | 1553 | g_profiler.stop(); |
| 1554 | 1554 | return; |
| r21559 | r21560 | |
| 1584 | 1584 | |
| 1585 | 1585 | /* perform color math if the layer wants it (except if it's an object > 192) */ |
| 1586 | 1586 | if (!scanline1->blend_exception[x] && m_layer[scanline1->layer[x]].color_math) |
| 1587 | | snes_draw_blend(x, &c, m_prevent_color_math, m_clip_to_black, 0); |
| 1587 | draw_blend(x, &c, m_prevent_color_math, m_clip_to_black, 0); |
| 1588 | 1588 | |
| 1589 | 1589 | r = ((c & 0x1f) * fade) >> 4; |
| 1590 | 1590 | g = (((c & 0x3e0) >> 5) * fade) >> 4; |
| r21559 | r21560 | |
| 1600 | 1600 | |
| 1601 | 1601 | /* perform color math if the layer wants it (except if it's an object > 192) */ |
| 1602 | 1602 | if (!scanline1->blend_exception[x] && m_layer[scanline1->layer[x]].color_math) |
| 1603 | | snes_draw_blend(x, &c, m_prevent_color_math, m_clip_to_black, 0); |
| 1603 | draw_blend(x, &c, m_prevent_color_math, m_clip_to_black, 0); |
| 1604 | 1604 | |
| 1605 | 1605 | tmp_col[1] = c; |
| 1606 | 1606 | |
| r21559 | r21560 | |
| 1613 | 1613 | apply to it the same color math as the *next* mainscreen pixel (i.e. mainscreen pixel 0), which seems as good as |
| 1614 | 1614 | any other choice */ |
| 1615 | 1615 | if (x == 0 && !scanline1->blend_exception[0] && m_layer[scanline1->layer[0]].color_math) |
| 1616 | | snes_draw_blend(0, &c, m_prevent_color_math, m_clip_to_black, 1); |
| 1616 | draw_blend(0, &c, m_prevent_color_math, m_clip_to_black, 1); |
| 1617 | 1617 | else if (x > 0 && !scanline1->blend_exception[x - 1] && m_layer[scanline1->layer[x - 1]].color_math) |
| 1618 | | snes_draw_blend(x, &c, m_prevent_color_math, m_clip_to_black, 1); |
| 1618 | draw_blend(x, &c, m_prevent_color_math, m_clip_to_black, 1); |
| 1619 | 1619 | |
| 1620 | 1620 | tmp_col[0] = c; |
| 1621 | 1621 | |
| r21559 | r21560 | |
| 1652 | 1652 | } |
| 1653 | 1653 | |
| 1654 | 1654 | void snes_ppu_class::ppu_start(running_machine &machine) |
| 1655 | | { |
| 1655 | { |
| 1656 | #if SNES_LAYER_DEBUG |
| 1657 | memset(&debug_options, 0, sizeof(debug_options)); |
| 1658 | #endif |
| 1659 | |
| 1656 | 1660 | m_vram = auto_alloc_array(machine, UINT8, SNES_VRAM_SIZE); |
| 1657 | 1661 | m_cgram = auto_alloc_array(machine, UINT16, SNES_CGRAM_SIZE/2); |
| 1658 | 1662 | m_oam_ram = auto_alloc_array(machine, UINT16, SNES_OAM_SIZE/2); |
| r21559 | r21560 | |
| 1668 | 1672 | m_ppu1_version = 1; // 5C77 chip version number, read by STAT77, only '1' is known |
| 1669 | 1673 | m_ppu2_version = 3; // 5C78 chip version number, read by STAT78, only '2' & '3' encountered so far. |
| 1670 | 1674 | |
| 1671 | | |
| 1675 | m_cgram_address = 0; |
| 1676 | m_read_ophct = 0; |
| 1677 | m_read_opvct = 0; |
| 1678 | |
| 1672 | 1679 | /* Inititialize mosaic table */ |
| 1673 | 1680 | for (int j = 0; j < 16; j++) |
| 1674 | 1681 | { |
| r21559 | r21560 | |
| 1772 | 1779 | state_save_register_global(machine, m_pseudo_hires); |
| 1773 | 1780 | state_save_register_global(machine, m_color_modes); |
| 1774 | 1781 | state_save_register_global(machine, m_stat77_flags); |
| 1782 | |
| 1783 | state_save_register_global(machine, m_htmult); |
| 1784 | state_save_register_global(machine, m_cgram_address); |
| 1785 | state_save_register_global(machine, m_read_ophct); |
| 1786 | state_save_register_global(machine, m_read_opvct); |
| 1787 | state_save_register_global(machine, m_vram_fgr_high); |
| 1788 | state_save_register_global(machine, m_vram_fgr_increment); |
| 1789 | state_save_register_global(machine, m_vram_fgr_count); |
| 1790 | state_save_register_global(machine, m_vram_fgr_mask); |
| 1791 | state_save_register_global(machine, m_vram_fgr_shift); |
| 1792 | state_save_register_global(machine, m_vram_read_buffer); |
| 1793 | state_save_register_global(machine, m_vmadd); |
| 1775 | 1794 | |
| 1776 | 1795 | state_save_register_global_pointer(machine, m_vram, SNES_VRAM_SIZE); |
| 1777 | 1796 | state_save_register_global_pointer(machine, m_cgram, SNES_CGRAM_SIZE/2); |
| 1778 | 1797 | state_save_register_global_pointer(machine, m_oam_ram, SNES_OAM_SIZE/2); |
| 1779 | 1798 | } |
| 1780 | 1799 | |
| 1781 | | VIDEO_START( snes ) |
| 1782 | | { |
| 1783 | | snes_state *state = machine.driver_data<snes_state>(); |
| 1784 | 1800 | |
| 1785 | | #if SNES_LAYER_DEBUG |
| 1786 | | memset(&debug_options, 0, sizeof(debug_options)); |
| 1787 | | #endif |
| 1788 | | |
| 1789 | | state->m_ppu.ppu_start(machine); |
| 1790 | | } |
| 1791 | | |
| 1792 | | UINT32 snes_state::snes_screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) |
| 1793 | | { |
| 1794 | | snes_state *state = machine().driver_data<snes_state>(); |
| 1795 | | int y; |
| 1796 | | |
| 1797 | | /*NTSC SNES draw range is 1-225. */ |
| 1798 | | for (y = cliprect.min_y; y <= cliprect.max_y; y++) |
| 1799 | | { |
| 1800 | | state->m_ppu.snes_refresh_scanline(machine(), bitmap, y + 1); |
| 1801 | | } |
| 1802 | | return 0; |
| 1803 | | } |
| 1804 | | |
| 1805 | | |
| 1806 | 1801 | /* CPU <-> PPU comms */ |
| 1807 | 1802 | |
| 1808 | 1803 | // full graphic variables |
| r21559 | r21560 | |
| 1811 | 1806 | static const UINT16 vram_fgr_shiftab[4] = { 0, 5, 6, 7 }; |
| 1812 | 1807 | |
| 1813 | 1808 | // utility function - latches the H/V counters. Used by IRQ, writes to WRIO, etc. |
| 1814 | | void snes_ppu_class::snes_latch_counters( running_machine &machine, UINT8 *ram_ptr ) |
| 1809 | void snes_ppu_class::latch_counters( running_machine &machine, UINT8 *ram_ptr ) |
| 1815 | 1810 | { |
| 1816 | | snes_state *state = machine.driver_data<snes_state>(); |
| 1817 | | |
| 1818 | | m_beam.current_horz = machine.primary_screen->hpos() / state->m_htmult; |
| 1811 | m_beam.current_horz = machine.primary_screen->hpos() / m_htmult; |
| 1819 | 1812 | m_beam.latch_vert = machine.primary_screen->vpos(); |
| 1820 | 1813 | m_beam.latch_horz = m_beam.current_horz; |
| 1821 | 1814 | ram_ptr[STAT78] |= 0x40; // indicate we latched |
| 1822 | | // state->m_read_ophct = state->m_read_opvct = 0; // clear read flags - 2009-08: I think we must clear these when STAT78 is read... |
| 1815 | // m_read_ophct = m_read_opvct = 0; // clear read flags - 2009-08: I think we must clear these when STAT78 is read... |
| 1823 | 1816 | |
| 1824 | 1817 | // printf("latched @ H %d V %d\n", m_beam.latch_horz, m_beam.latch_vert); |
| 1825 | 1818 | } |
| 1826 | 1819 | |
| 1827 | | void snes_ppu_class::snes_dynamic_res_change( running_machine &machine, UINT8 *ram_ptr ) |
| 1820 | void snes_ppu_class::dynamic_res_change( running_machine &machine, UINT8 *ram_ptr ) |
| 1828 | 1821 | { |
| 1829 | | snes_state *state = machine.driver_data<snes_state>(); |
| 1830 | 1822 | rectangle visarea = machine.primary_screen->visible_area(); |
| 1831 | 1823 | attoseconds_t refresh; |
| 1832 | 1824 | |
| r21559 | r21560 | |
| 1836 | 1828 | |
| 1837 | 1829 | // fixme: should compensate for SNES_DBG_VIDEO |
| 1838 | 1830 | if (m_mode == 5 || m_mode == 6 || m_pseudo_hires) |
| 1839 | | state->m_htmult = 2; |
| 1831 | m_htmult = 2; |
| 1840 | 1832 | else |
| 1841 | | state->m_htmult = 1; |
| 1833 | m_htmult = 1; |
| 1842 | 1834 | |
| 1843 | 1835 | /* FIXME: does the timing changes when the gfx mode is equal to 5 or 6? */ |
| 1844 | 1836 | if ((ram_ptr[STAT78] & 0x10) == SNES_NTSC) |
| r21559 | r21560 | |
| 1868 | 1860 | when interlace is active. |
| 1869 | 1861 | *************************************************/ |
| 1870 | 1862 | |
| 1871 | | inline UINT32 snes_ppu_class::snes_get_vram_address( running_machine &machine ) |
| 1863 | inline UINT32 snes_ppu_class::get_vram_address( running_machine &machine ) |
| 1872 | 1864 | { |
| 1873 | | snes_state *state = machine.driver_data<snes_state>(); |
| 1874 | | UINT32 addr = state->m_vmadd; |
| 1865 | UINT32 addr = m_vmadd; |
| 1875 | 1866 | |
| 1876 | | if (state->m_vram_fgr_count) |
| 1867 | if (m_vram_fgr_count) |
| 1877 | 1868 | { |
| 1878 | | UINT32 rem = addr & state->m_vram_fgr_mask; |
| 1879 | | UINT32 faddr = (addr & ~state->m_vram_fgr_mask) + (rem >> state->m_vram_fgr_shift) + ((rem & (state->m_vram_fgr_count - 1)) << 3); |
| 1869 | UINT32 rem = addr & m_vram_fgr_mask; |
| 1870 | UINT32 faddr = (addr & ~m_vram_fgr_mask) + (rem >> m_vram_fgr_shift) + ((rem & (m_vram_fgr_count - 1)) << 3); |
| 1880 | 1871 | return faddr << 1; |
| 1881 | 1872 | } |
| 1882 | 1873 | |
| 1883 | 1874 | return addr << 1; |
| 1884 | 1875 | } |
| 1885 | 1876 | |
| 1886 | | READ8_MEMBER( snes_ppu_class::snes_vram_read ) |
| 1877 | READ8_MEMBER( snes_ppu_class::vram_read ) |
| 1887 | 1878 | { |
| 1888 | 1879 | UINT8 res = 0; |
| 1889 | 1880 | offset &= 0xffff; // only 64KB are present on SNES |
| r21559 | r21560 | |
| 1919 | 1910 | return res; |
| 1920 | 1911 | } |
| 1921 | 1912 | |
| 1922 | | WRITE8_MEMBER( snes_ppu_class::snes_vram_write ) |
| 1913 | WRITE8_MEMBER( snes_ppu_class::vram_write ) |
| 1923 | 1914 | { |
| 1924 | 1915 | offset &= 0xffff; // only 64KB are present on SNES, Robocop 3 relies on this |
| 1925 | 1916 | |
| r21559 | r21560 | |
| 1984 | 1975 | to choose the high/low byte of the snes_oam word. |
| 1985 | 1976 | *************************************************/ |
| 1986 | 1977 | |
| 1987 | | READ8_MEMBER( snes_ppu_class::snes_oam_read ) |
| 1978 | READ8_MEMBER( snes_ppu_class::oam_read ) |
| 1988 | 1979 | { |
| 1989 | 1980 | offset &= 0x1ff; |
| 1990 | 1981 | |
| r21559 | r21560 | |
| 2002 | 1993 | return (m_oam_ram[offset] >> (snes_ram[OAMDATA] << 3)) & 0xff; |
| 2003 | 1994 | } |
| 2004 | 1995 | |
| 2005 | | WRITE8_MEMBER( snes_ppu_class::snes_oam_write ) |
| 1996 | WRITE8_MEMBER( snes_ppu_class::oam_write ) |
| 2006 | 1997 | { |
| 2007 | 1998 | offset &= 0x1ff; |
| 2008 | 1999 | |
| r21559 | r21560 | |
| 2044 | 2035 | solution adopted by BSNES without enabling it. |
| 2045 | 2036 | *************************************************/ |
| 2046 | 2037 | |
| 2047 | | READ8_MEMBER( snes_ppu_class::snes_cgram_read ) |
| 2038 | READ8_MEMBER( snes_ppu_class::cgram_read ) |
| 2048 | 2039 | { |
| 2049 | 2040 | UINT8 res = 0; |
| 2050 | 2041 | offset &= 0x1ff; |
| r21559 | r21560 | |
| 2070 | 2061 | return res; |
| 2071 | 2062 | } |
| 2072 | 2063 | |
| 2073 | | WRITE8_MEMBER( snes_ppu_class::snes_cgram_write ) |
| 2064 | WRITE8_MEMBER( snes_ppu_class::cgram_write ) |
| 2074 | 2065 | { |
| 2075 | 2066 | offset &= 0x1ff; |
| 2076 | 2067 | |
| r21559 | r21560 | |
| 2096 | 2087 | ((UINT8 *)m_cgram)[offset] = data; |
| 2097 | 2088 | } |
| 2098 | 2089 | |
| 2099 | | UINT8 snes_ppu_class::snes_ppu_read(address_space &space, UINT32 offset, UINT8 *ram_ptr) |
| 2090 | UINT8 snes_ppu_class::read(address_space &space, UINT32 offset, UINT8 *ram_ptr) |
| 2100 | 2091 | { |
| 2101 | | snes_state *state = space.machine().driver_data<snes_state>(); |
| 2102 | 2092 | UINT8 value; |
| 2103 | 2093 | |
| 2104 | 2094 | switch (offset) |
| r21559 | r21560 | |
| 2145 | 2135 | return m_ppu1_open_bus; |
| 2146 | 2136 | } |
| 2147 | 2137 | case SLHV: /* Software latch for H/V counter */ |
| 2148 | | snes_latch_counters(space.machine(), ram_ptr); |
| 2138 | latch_counters(space.machine(), ram_ptr); |
| 2149 | 2139 | return snes_open_bus_r(space, 0); /* Return value is meaningless */ |
| 2150 | 2140 | case ROAMDATA: /* Read data from OAM (DR) */ |
| 2151 | | m_ppu1_open_bus = snes_oam_read(space, m_oam.address); |
| 2141 | m_ppu1_open_bus = oam_read(space, m_oam.address); |
| 2152 | 2142 | ram_ptr[OAMDATA] = (ram_ptr[OAMDATA] + 1) % 2; |
| 2153 | 2143 | if (!ram_ptr[OAMDATA]) |
| 2154 | 2144 | { |
| r21559 | r21560 | |
| 2159 | 2149 | return m_ppu1_open_bus; |
| 2160 | 2150 | case RVMDATAL: /* Read data from VRAM (low) */ |
| 2161 | 2151 | { |
| 2162 | | UINT32 addr = snes_get_vram_address(space.machine()); |
| 2163 | | m_ppu1_open_bus = state->m_vram_read_buffer & 0xff; |
| 2152 | UINT32 addr = get_vram_address(space.machine()); |
| 2153 | m_ppu1_open_bus = m_vram_read_buffer & 0xff; |
| 2164 | 2154 | |
| 2165 | | if (!state->m_vram_fgr_high) |
| 2155 | if (!m_vram_fgr_high) |
| 2166 | 2156 | { |
| 2167 | | state->m_vram_read_buffer = snes_vram_read(space, addr); |
| 2168 | | state->m_vram_read_buffer |= (snes_vram_read(space, addr + 1) << 8); |
| 2157 | m_vram_read_buffer = vram_read(space, addr); |
| 2158 | m_vram_read_buffer |= (vram_read(space, addr + 1) << 8); |
| 2169 | 2159 | |
| 2170 | | state->m_vmadd = (state->m_vmadd + state->m_vram_fgr_increment) & 0xffff; |
| 2160 | m_vmadd = (m_vmadd + m_vram_fgr_increment) & 0xffff; |
| 2171 | 2161 | } |
| 2172 | 2162 | |
| 2173 | 2163 | return m_ppu1_open_bus; |
| 2174 | 2164 | } |
| 2175 | 2165 | case RVMDATAH: /* Read data from VRAM (high) */ |
| 2176 | 2166 | { |
| 2177 | | UINT32 addr = snes_get_vram_address(space.machine()); |
| 2178 | | m_ppu1_open_bus = (state->m_vram_read_buffer >> 8) & 0xff; |
| 2167 | UINT32 addr = get_vram_address(space.machine()); |
| 2168 | m_ppu1_open_bus = (m_vram_read_buffer >> 8) & 0xff; |
| 2179 | 2169 | |
| 2180 | | if (state->m_vram_fgr_high) |
| 2170 | if (m_vram_fgr_high) |
| 2181 | 2171 | { |
| 2182 | | state->m_vram_read_buffer = snes_vram_read(space, addr); |
| 2183 | | state->m_vram_read_buffer |= (snes_vram_read(space, addr + 1) << 8); |
| 2172 | m_vram_read_buffer = vram_read(space, addr); |
| 2173 | m_vram_read_buffer |= (vram_read(space, addr + 1) << 8); |
| 2184 | 2174 | |
| 2185 | | state->m_vmadd = (state->m_vmadd + state->m_vram_fgr_increment) & 0xffff; |
| 2175 | m_vmadd = (m_vmadd + m_vram_fgr_increment) & 0xffff; |
| 2186 | 2176 | } |
| 2187 | 2177 | |
| 2188 | 2178 | return m_ppu1_open_bus; |
| 2189 | 2179 | } |
| 2190 | 2180 | case RCGDATA: /* Read data from CGRAM */ |
| 2191 | | if (!(state->m_cgram_address & 0x01)) |
| 2192 | | m_ppu2_open_bus = snes_cgram_read(space, state->m_cgram_address); |
| 2181 | if (!(m_cgram_address & 0x01)) |
| 2182 | m_ppu2_open_bus = cgram_read(space, m_cgram_address); |
| 2193 | 2183 | else |
| 2194 | 2184 | { |
| 2195 | 2185 | m_ppu2_open_bus &= 0x80; |
| 2196 | | m_ppu2_open_bus |= snes_cgram_read(space, state->m_cgram_address) & 0x7f; |
| 2186 | m_ppu2_open_bus |= cgram_read(space, m_cgram_address) & 0x7f; |
| 2197 | 2187 | } |
| 2198 | 2188 | |
| 2199 | | state->m_cgram_address = (state->m_cgram_address + 1) % (SNES_CGRAM_SIZE - 2); |
| 2189 | m_cgram_address = (m_cgram_address + 1) % (SNES_CGRAM_SIZE - 2); |
| 2200 | 2190 | return m_ppu2_open_bus; |
| 2201 | 2191 | case OPHCT: /* Horizontal counter data by ext/soft latch */ |
| 2202 | | if (state->m_read_ophct) |
| 2192 | if (m_read_ophct) |
| 2203 | 2193 | { |
| 2204 | 2194 | m_ppu2_open_bus &= 0xfe; |
| 2205 | 2195 | m_ppu2_open_bus |= (m_beam.latch_horz >> 8) & 0x01; |
| r21559 | r21560 | |
| 2208 | 2198 | { |
| 2209 | 2199 | m_ppu2_open_bus = m_beam.latch_horz & 0xff; |
| 2210 | 2200 | } |
| 2211 | | state->m_read_ophct ^= 1; |
| 2201 | m_read_ophct ^= 1; |
| 2212 | 2202 | return m_ppu2_open_bus; |
| 2213 | 2203 | case OPVCT: /* Vertical counter data by ext/soft latch */ |
| 2214 | | if (state->m_read_opvct) |
| 2204 | if (m_read_opvct) |
| 2215 | 2205 | { |
| 2216 | 2206 | m_ppu2_open_bus &= 0xfe; |
| 2217 | 2207 | m_ppu2_open_bus |= (m_beam.latch_vert >> 8) & 0x01; |
| r21559 | r21560 | |
| 2220 | 2210 | { |
| 2221 | 2211 | m_ppu2_open_bus = m_beam.latch_vert & 0xff; |
| 2222 | 2212 | } |
| 2223 | | state->m_read_opvct ^= 1; |
| 2213 | m_read_opvct ^= 1; |
| 2224 | 2214 | return m_ppu2_open_bus; |
| 2225 | 2215 | case STAT77: /* PPU status flag and version number */ |
| 2226 | 2216 | value = m_stat77_flags & 0xc0; // 0x80 & 0x40 are Time Over / Range Over Sprite flags, set by the video code |
| r21559 | r21560 | |
| 2231 | 2221 | m_ppu1_open_bus = value; |
| 2232 | 2222 | return m_ppu1_open_bus; |
| 2233 | 2223 | case STAT78: /* PPU status flag and version number */ |
| 2234 | | state->m_read_ophct = 0; |
| 2235 | | state->m_read_opvct = 0; |
| 2224 | m_read_ophct = 0; |
| 2225 | m_read_opvct = 0; |
| 2236 | 2226 | if(ram_ptr[WRIO] & 0x80) |
| 2237 | 2227 | ram_ptr[STAT78] &= ~0x40; //clear ext latch if bit 7 of WRIO is set |
| 2238 | 2228 | ram_ptr[STAT78] = (ram_ptr[STAT78] & ~0x2f) | (m_ppu2_open_bus & 0x20) | (m_ppu2_version & 0x0f); |
| r21559 | r21560 | |
| 2245 | 2235 | } |
| 2246 | 2236 | |
| 2247 | 2237 | |
| 2248 | | void snes_ppu_class::snes_ppu_write(address_space &space, UINT32 offset, UINT8 data, UINT8 *ram_ptr) |
| 2238 | void snes_ppu_class::write(address_space &space, UINT32 offset, UINT8 data, UINT8 *ram_ptr) |
| 2249 | 2239 | { |
| 2250 | | snes_state *state = space.machine().driver_data<snes_state>(); |
| 2251 | | |
| 2252 | 2240 | switch (offset) |
| 2253 | 2241 | { |
| 2254 | 2242 | case INIDISP: /* Initial settings for screen */ |
| r21559 | r21560 | |
| 2281 | 2269 | break; |
| 2282 | 2270 | case OAMDATA: /* Data for OAM write (DW) */ |
| 2283 | 2271 | if (m_oam.address >= 0x100) |
| 2284 | | snes_oam_write(space, m_oam.address, data); |
| 2272 | oam_write(space, m_oam.address, data); |
| 2285 | 2273 | else |
| 2286 | 2274 | { |
| 2287 | 2275 | if (!ram_ptr[OAMDATA]) |
| r21559 | r21560 | |
| 2291 | 2279 | // in this case, we not only write data to the upper byte of the word, |
| 2292 | 2280 | // but also m_oam.write_latch to the lower byte (recall that |
| 2293 | 2281 | // ram_ptr[OAMDATA] is used to select high/low byte) |
| 2294 | | snes_oam_write(space, m_oam.address, data); |
| 2282 | oam_write(space, m_oam.address, data); |
| 2295 | 2283 | ram_ptr[OAMDATA] = 0; |
| 2296 | | snes_oam_write(space, m_oam.address, m_oam.write_latch); |
| 2284 | oam_write(space, m_oam.address, m_oam.write_latch); |
| 2297 | 2285 | ram_ptr[OAMDATA] = 1; |
| 2298 | 2286 | } |
| 2299 | 2287 | } |
| r21559 | r21560 | |
| 2307 | 2295 | return; |
| 2308 | 2296 | case BGMODE: /* BG mode and character size settings */ |
| 2309 | 2297 | m_mode = data & 0x07; |
| 2310 | | snes_dynamic_res_change(space.machine(), ram_ptr); |
| 2298 | dynamic_res_change(space.machine(), ram_ptr); |
| 2311 | 2299 | m_bg3_priority_bit = BIT(data, 3); |
| 2312 | 2300 | m_layer[SNES_BG1].tile_size = BIT(data, 4); |
| 2313 | 2301 | m_layer[SNES_BG2].tile_size = BIT(data, 5); |
| r21559 | r21560 | |
| 2388 | 2376 | m_update_offsets = 1; |
| 2389 | 2377 | return; |
| 2390 | 2378 | case VMAIN: /* VRAM address increment value designation */ |
| 2391 | | state->m_vram_fgr_high = (data & 0x80); |
| 2392 | | state->m_vram_fgr_increment = vram_fgr_inctab[data & 3]; |
| 2379 | m_vram_fgr_high = (data & 0x80); |
| 2380 | m_vram_fgr_increment = vram_fgr_inctab[data & 3]; |
| 2393 | 2381 | |
| 2394 | 2382 | if (data & 0xc) |
| 2395 | 2383 | { |
| 2396 | 2384 | int md = (data & 0xc) >> 2; |
| 2397 | 2385 | |
| 2398 | | state->m_vram_fgr_count = vram_fgr_inccnts[md]; // 0x20, 0x40, 0x80 |
| 2399 | | state->m_vram_fgr_mask = (state->m_vram_fgr_count * 8) - 1; // 0xff, 0x1ff, 0x2ff |
| 2400 | | state->m_vram_fgr_shift = vram_fgr_shiftab[md]; // 5, 6, 7 |
| 2386 | m_vram_fgr_count = vram_fgr_inccnts[md]; // 0x20, 0x40, 0x80 |
| 2387 | m_vram_fgr_mask = (m_vram_fgr_count * 8) - 1; // 0xff, 0x1ff, 0x2ff |
| 2388 | m_vram_fgr_shift = vram_fgr_shiftab[md]; // 5, 6, 7 |
| 2401 | 2389 | } |
| 2402 | 2390 | else |
| 2403 | 2391 | { |
| 2404 | | state->m_vram_fgr_count = 0; |
| 2392 | m_vram_fgr_count = 0; |
| 2405 | 2393 | } |
| 2406 | | // printf("VMAIN: high %x inc %x count %x mask %x shift %x\n", state->m_vram_fgr_high, state->m_vram_fgr_increment, state->m_vram_fgr_count, state->m_vram_fgr_mask, state->m_vram_fgr_shift); |
| 2394 | // printf("VMAIN: high %x inc %x count %x mask %x shift %x\n", m_vram_fgr_high, m_vram_fgr_increment, m_vram_fgr_count, m_vram_fgr_mask, m_vram_fgr_shift); |
| 2407 | 2395 | break; |
| 2408 | 2396 | case VMADDL: /* Address for VRAM read/write (low) */ |
| 2409 | 2397 | { |
| 2410 | 2398 | UINT32 addr; |
| 2411 | | state->m_vmadd = (state->m_vmadd & 0xff00) | (data << 0); |
| 2412 | | addr = snes_get_vram_address(space.machine()); |
| 2413 | | state->m_vram_read_buffer = snes_vram_read(space, addr); |
| 2414 | | state->m_vram_read_buffer |= (snes_vram_read(space, addr + 1) << 8); |
| 2399 | m_vmadd = (m_vmadd & 0xff00) | (data << 0); |
| 2400 | addr = get_vram_address(space.machine()); |
| 2401 | m_vram_read_buffer = vram_read(space, addr); |
| 2402 | m_vram_read_buffer |= (vram_read(space, addr + 1) << 8); |
| 2415 | 2403 | } |
| 2416 | 2404 | break; |
| 2417 | 2405 | case VMADDH: /* Address for VRAM read/write (high) */ |
| 2418 | 2406 | { |
| 2419 | 2407 | UINT32 addr; |
| 2420 | | state->m_vmadd = (state->m_vmadd & 0x00ff) | (data << 8); |
| 2421 | | addr = snes_get_vram_address(space.machine()); |
| 2422 | | state->m_vram_read_buffer = snes_vram_read(space, addr); |
| 2423 | | state->m_vram_read_buffer |= (snes_vram_read(space, addr + 1) << 8); |
| 2408 | m_vmadd = (m_vmadd & 0x00ff) | (data << 8); |
| 2409 | addr = get_vram_address(space.machine()); |
| 2410 | m_vram_read_buffer = vram_read(space, addr); |
| 2411 | m_vram_read_buffer |= (vram_read(space, addr + 1) << 8); |
| 2424 | 2412 | } |
| 2425 | 2413 | break; |
| 2426 | 2414 | case VMDATAL: /* 2118: Data for VRAM write (low) */ |
| 2427 | 2415 | { |
| 2428 | | UINT32 addr = snes_get_vram_address(space.machine()); |
| 2429 | | snes_vram_write(space, addr, data); |
| 2416 | UINT32 addr = get_vram_address(space.machine()); |
| 2417 | vram_write(space, addr, data); |
| 2430 | 2418 | |
| 2431 | | if (!state->m_vram_fgr_high) |
| 2432 | | state->m_vmadd = (state->m_vmadd + state->m_vram_fgr_increment) & 0xffff; |
| 2419 | if (!m_vram_fgr_high) |
| 2420 | m_vmadd = (m_vmadd + m_vram_fgr_increment) & 0xffff; |
| 2433 | 2421 | } |
| 2434 | 2422 | return; |
| 2435 | 2423 | case VMDATAH: /* 2119: Data for VRAM write (high) */ |
| 2436 | 2424 | { |
| 2437 | | UINT32 addr = snes_get_vram_address(space.machine()); |
| 2438 | | snes_vram_write(space, addr + 1, data); |
| 2425 | UINT32 addr = get_vram_address(space.machine()); |
| 2426 | vram_write(space, addr + 1, data); |
| 2439 | 2427 | |
| 2440 | | if (state->m_vram_fgr_high) |
| 2441 | | state->m_vmadd = (state->m_vmadd + state->m_vram_fgr_increment) & 0xffff; |
| 2428 | if (m_vram_fgr_high) |
| 2429 | m_vmadd = (m_vmadd + m_vram_fgr_increment) & 0xffff; |
| 2442 | 2430 | } |
| 2443 | 2431 | return; |
| 2444 | 2432 | case M7SEL: /* Mode 7 initial settings */ |
| r21559 | r21560 | |
| 2473 | 2461 | break; |
| 2474 | 2462 | case CGADD: /* Initial address for colour RAM writing */ |
| 2475 | 2463 | /* CGRAM is 16-bit, but when reading/writing we treat it as 8-bit, so we need to double the address */ |
| 2476 | | state->m_cgram_address = data << 1; |
| 2464 | m_cgram_address = data << 1; |
| 2477 | 2465 | break; |
| 2478 | 2466 | case CGDATA: /* Data for colour RAM */ |
| 2479 | | snes_cgram_write(space, state->m_cgram_address, data); |
| 2480 | | state->m_cgram_address = (state->m_cgram_address + 1) % (SNES_CGRAM_SIZE - 2); |
| 2467 | cgram_write(space, m_cgram_address, data); |
| 2468 | m_cgram_address = (m_cgram_address + 1) % (SNES_CGRAM_SIZE - 2); |
| 2481 | 2469 | break; |
| 2482 | 2470 | case W12SEL: /* Window mask settings for BG1-2 */ |
| 2483 | 2471 | if (data != ram_ptr[offset]) |
| r21559 | r21560 | |
| 2638 | 2626 | m_beam.last_visible_line = (data & 0x04) ? 240 : 225; |
| 2639 | 2627 | m_pseudo_hires = BIT(data, 3); |
| 2640 | 2628 | m_mode7.extbg = BIT(data, 6); |
| 2641 | | snes_dynamic_res_change(space.machine(), ram_ptr); |
| 2629 | dynamic_res_change(space.machine(), ram_ptr); |
| 2642 | 2630 | #ifdef SNES_DBG_REG_W |
| 2643 | 2631 | if ((data & 0x8) != (ram_ptr[SETINI] & 0x8)) |
| 2644 | 2632 | mame_printf_debug("Pseudo 512 mode: %s\n", (data & 0x8) ? "on" : "off"); |
| r21559 | r21560 | |
| 2665 | 2653 | popmessage MSG2; \ |
| 2666 | 2654 | } |
| 2667 | 2655 | |
| 2668 | | static UINT8 snes_dbg_video( running_machine &machine, UINT16 curline, UINT8 *ram_ptr ) |
| 2656 | static UINT8 dbg_video( running_machine &machine, UINT16 curline, UINT8 *ram_ptr ) |
| 2669 | 2657 | { |
| 2670 | 2658 | int i; |
| 2671 | 2659 | UINT8 toggles = machine.root_device().ioport("DEBUG1")->read_safe(0); |