| Previous | 199869 Revisions | Next |
| r31076 Sunday 22nd June, 2014 at 20:08:43 UTC by Wilbert Pol |
|---|
| (MESS) sms.c: Several timing fixes: [Enik Land] - Fix flicker on Choplifter title screen by drawing the borders through timers. - Instead trigger NMI at end of the display, do it at end of top border (line 261 after start of active screen area). - Add a delay to NMI, to be later than HINT, as stated by Flubba's VDPTest readme. - Also based on VDPTest readme, change VINT and Sprite Overflow flags to be later than VCount change. - Delay a little the display callback, to fix the title scrolling of Road Rash (SMS game). - Fixed documentation of the scanline sections and change some timings to match. - Calculate initial VCount values, instead use of hardcoded values. |
| [src/emu/video] | 315_5124.c 315_5124.h |
| r31075 | r31076 | |
|---|---|---|
| 22 | 22 | - http://www.smspower.org/forums/viewtopic.php?p=44198 |
| 23 | 23 | |
| 24 | 24 | A scanline contains the following sections: |
| 25 | - horizontal sync | |
| 25 | - horizontal sync 9 E9-ED => HSYNC high | |
| 26 | 26 | - left blanking 2 ED-EE |
| 27 | - color burst 14 EE- | |
| 27 | - color burst 14 EE-F5 => increment line counter/generate interrupts/etc | |
| 28 | 28 | - left blanking 8 F5-F9 |
| 29 | 29 | - left border 13 F9-FF |
| 30 | 30 | - active display 256 00-7F |
| 31 | 31 | - right border 15 80-87 |
| 32 | 32 | - right blanking 8 87-8B |
| 33 | - horizontal sync | |
| 33 | - horizontal sync 17 8B-93 => HSYNC low | |
| 34 | 34 | |
| 35 | 35 | |
| 36 | 36 | NTSC frame timing |
| 37 | 37 | 256x192 256x224 256x240 (doesn't work on real hardware) |
| 38 | - vertical blanking 3 D5-D7 3 E5-E7 3 EE-F0 | |
| 39 | - top blanking 13 D8-E4 13 E8-F4 13 F1-FD | |
| 38 | - vertical blanking 3 D5-D7 3 E5-E7 3 ED-EF | |
| 39 | - top blanking 13 D8-E4 13 E8-F4 13 F0-FC | |
| 40 | 40 | - top border 27 E5-FF 11 F5-FF 3 FD-FF |
| 41 | 41 | - active display 192 00-BF 224 00-DF 240 00-EF |
| 42 | 42 | - bottom border 24 C0-D7 8 E0-E7 0 F0-F0 |
| r31075 | r31076 | |
| 64 | 64 | #define STATUS_HINT 0x02 /* Pending horizontal interrupt flag */ |
| 65 | 65 | |
| 66 | 66 | #define VINT_HPOS 24 |
| 67 | #define VINT_FLAG_HPOS 2 | |
| 67 | #define VINT_FLAG_HPOS 24 | |
| 68 | 68 | #define HINT_HPOS 26 |
| 69 | #define NMI_HPOS 28 | |
| 69 | 70 | #define VCOUNT_CHANGE_HPOS 23 |
| 70 | #define SPROVR_HPOS 2 | |
| 71 | #define SPROVR_HPOS 24 | |
| 71 | 72 | #define SPRCOL_BASEHPOS 59 |
| 72 | 73 | #define X_SCROLL_HPOS 21 |
| 73 | 74 | #define DISPLAY_DISABLED_HPOS 17 /* fixes 'fantdizzy' (SMS PAL game) flicker */ |
| 74 | #define DISPLAY_CB_HPOS | |
| 75 | #define DISPLAY_CB_HPOS 2 /* fixes 'roadrash' (SMS game) title scrolling, due to line counter reload timing */ | |
| 75 | 76 | |
| 76 | #define DRAW_TIME_GG 86 /* 1 + 2 + 14 + 8 + 122/2 */ | |
| 77 | #define DRAW_TIME_SMS 25 /* 1 + 2 + 14 + 8 */ | |
| 77 | #define DRAW_TIME_GG 94 /* 9 + 2 + 14 + 8 + 13 + 96/2 */ | |
| 78 | #define DRAW_TIME_SMS 46 /* 9 + 2 + 14 + 8 + 13 */ | |
| 78 | 79 | |
| 79 | 80 | #define PRIORITY_BIT 0x1000 |
| 80 | 81 | #define BACKDROP_COLOR ((m_vdp_mode == 4 ? 0x10 : 0x00) + (m_reg[0x07] & 0x0f)) |
| 81 | 82 | |
| 82 | #define INIT_VCOUNT 0 | |
| 83 | #define VERTICAL_BLANKING 1 | |
| 84 | #define TOP_BLANKING 2 | |
| 85 | #define TOP_BORDER 3 | |
| 86 | #define ACTIVE_DISPLAY_V 4 | |
| 87 | #define BOTTOM_BORDER 5 | |
| 88 | #define BOTTOM_BLANKING 6 | |
| 83 | #define VERTICAL_BLANKING 0 | |
| 84 | #define TOP_BLANKING 1 | |
| 85 | #define TOP_BORDER 2 | |
| 86 | #define ACTIVE_DISPLAY_V 3 | |
| 87 | #define BOTTOM_BORDER 4 | |
| 88 | #define BOTTOM_BLANKING 5 | |
| 89 | 89 | |
| 90 | static const UINT8 ntsc_192[7] = { 0xd5, 3, 13, 27, 192, 24, 3 }; | |
| 91 | static const UINT8 ntsc_224[7] = { 0xe5, 3, 13, 11, 224, 8, 3 }; | |
| 92 | static const UINT8 ntsc_240[7] = { 0xee, 3, 13, 3, 240, 0, 3 }; | |
| 93 | static const UINT8 pal_192[7] = { 0xba, 3, 13, 54, 192, 48, 3 }; | |
| 94 | static const UINT8 pal_224[7] = { 0xca, 3, 13, 38, 224, 32, 3 }; | |
| 95 | static const UINT8 pal_240[7] = { 0xd2, 3, 13, 30, 240, 24, 3 }; | |
| 90 | static const UINT8 ntsc_192[6] = { 3, 13, 27, 192, 24, 3 }; | |
| 91 | static const UINT8 ntsc_224[6] = { 3, 13, 11, 224, 8, 3 }; | |
| 92 | static const UINT8 ntsc_240[6] = { 3, 13, 3, 240, 0, 3 }; | |
| 93 | static const UINT8 pal_192[6] = { 3, 13, 54, 192, 48, 3 }; | |
| 94 | static const UINT8 pal_224[6] = { 3, 13, 38, 224, 32, 3 }; | |
| 95 | static const UINT8 pal_240[6] = { 3, 13, 30, 240, 24, 3 }; | |
| 96 | 96 | |
| 97 | 97 | |
| 98 | 98 | const device_type SEGA315_5124 = &device_creator<sega315_5124_device>; |
| r31075 | r31076 | |
| 273 | 273 | READ8_MEMBER( sega315_5124_device::vcount_read ) |
| 274 | 274 | { |
| 275 | 275 | int vpos = m_screen->vpos(); |
| 276 | int active_scr_start = m_frame_timing[VERTICAL_BLANKING] + m_frame_timing[TOP_BLANKING] + m_frame_timing[TOP_BORDER]; | |
| 276 | 277 | |
| 277 | 278 | if (m_screen->hpos() < VCOUNT_CHANGE_HPOS) |
| 278 | 279 | { |
| r31075 | r31076 | |
| 281 | 282 | vpos += m_screen->height(); |
| 282 | 283 | } |
| 283 | 284 | |
| 284 | return ( | |
| 285 | return (vpos - active_scr_start) & 0xff; | |
| 285 | 286 | } |
| 286 | 287 | |
| 287 | 288 | |
| r31075 | r31076 | |
| 325 | 326 | draw_scanline( SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH, param, m_screen->vpos() - param ); |
| 326 | 327 | break; |
| 327 | 328 | |
| 328 | case TIMER_CHECK_HINT: | |
| 329 | case TIMER_LBORDER: | |
| 330 | { | |
| 331 | rectangle rec; | |
| 332 | rec.min_y = rec.max_y = param; | |
| 333 | ||
| 334 | update_palette(); | |
| 335 | ||
| 336 | /* Draw left border */ | |
| 337 | rec.min_x = SEGA315_5124_LBORDER_START; | |
| 338 | rec.max_x = SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH - 1; | |
| 339 | m_tmpbitmap.fill(m_palette->pen(m_current_palette[BACKDROP_COLOR]), rec); | |
| 340 | m_y1_bitmap.fill(1, rec); | |
| 341 | } | |
| 342 | break; | |
| 343 | ||
| 344 | case TIMER_RBORDER: | |
| 345 | { | |
| 346 | rectangle rec; | |
| 347 | rec.min_y = rec.max_y = param; | |
| 348 | ||
| 349 | update_palette(); | |
| 350 | ||
| 351 | /* Draw right border */ | |
| 352 | rec.min_x = SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH + 256; | |
| 353 | rec.max_x = rec.min_x + SEGA315_5124_RBORDER_WIDTH - 1; | |
| 354 | m_tmpbitmap.fill(m_palette->pen(m_current_palette[BACKDROP_COLOR]), rec); | |
| 355 | m_y1_bitmap.fill(1, rec); | |
| 356 | } | |
| 357 | break; | |
| 358 | ||
| 359 | case TIMER_HINT: | |
| 329 | 360 | if ((m_pending_status & STATUS_HINT) || (m_status & STATUS_HINT)) |
| 330 | 361 | { |
| 331 | 362 | if ((m_reg[0x00] & 0x10)) |
| r31075 | r31076 | |
| 338 | 369 | } |
| 339 | 370 | break; |
| 340 | 371 | |
| 341 | case TIMER_ | |
| 372 | case TIMER_VINT: | |
| 342 | 373 | if ((m_pending_status & STATUS_VINT) || (m_status & STATUS_VINT)) |
| 343 | 374 | { |
| 344 | 375 | if ((m_reg[0x01] & 0x20)) |
| r31075 | r31076 | |
| 350 | 381 | } |
| 351 | 382 | } |
| 352 | 383 | break; |
| 384 | ||
| 385 | case TIMER_NMI: | |
| 386 | if ( !m_pause_cb.isnull() ) | |
| 387 | m_pause_cb(0); | |
| 388 | break; | |
| 353 | 389 | } |
| 354 | 390 | } |
| 355 | 391 | |
| 356 | 392 | |
| 357 | 393 | void sega315_5124_device::process_line_timer() |
| 358 | 394 | { |
| 359 | rectangle rec; | |
| 360 | 395 | int vpos = m_screen->vpos(); |
| 361 | 396 | int vpos_limit = m_frame_timing[VERTICAL_BLANKING] + m_frame_timing[TOP_BLANKING] |
| 362 | 397 | + m_frame_timing[TOP_BORDER] + m_frame_timing[ACTIVE_DISPLAY_V] |
| 363 | 398 | + m_frame_timing[BOTTOM_BORDER] + m_frame_timing[BOTTOM_BLANKING]; |
| 364 | 399 | |
| 365 | rec.min_y = rec.max_y = vpos; | |
| 366 | ||
| 367 | 400 | m_display_disabled = !(m_reg[0x01] & 0x40); |
| 368 | 401 | |
| 369 | /* Check if we're on the last line of a frame */ | |
| 370 | if (vpos == vpos_limit - 1) | |
| 371 | { | |
| 372 | m_line_counter = m_reg[0x0a]; | |
| 373 | if ( !m_pause_cb.isnull() ) | |
| 374 | m_pause_cb(0); | |
| 402 | /* Activate flags that were pending until the end of previous line. */ | |
| 403 | check_pending_flags(); | |
| 375 | 404 | |
| 376 | return; | |
| 377 | } | |
| 378 | ||
| 379 | 405 | vpos_limit -= m_frame_timing[BOTTOM_BLANKING]; |
| 380 | 406 | |
| 381 | 407 | /* Check if we're below the bottom border */ |
| r31075 | r31076 | |
| 395 | 421 | if (m_line_counter == 0x00) |
| 396 | 422 | { |
| 397 | 423 | m_line_counter = m_reg[0x0a]; |
| 398 | m_ | |
| 424 | m_hint_timer->adjust( m_screen->time_until_pos( vpos, HINT_HPOS ) ); | |
| 399 | 425 | m_pending_status |= STATUS_HINT; |
| 400 | 426 | } |
| 401 | 427 | else |
| r31075 | r31076 | |
| 410 | 436 | |
| 411 | 437 | if (vpos == vpos_limit + 1) |
| 412 | 438 | { |
| 413 | m_ | |
| 439 | m_vint_timer->adjust( m_screen->time_until_pos( vpos, VINT_HPOS ) ); | |
| 414 | 440 | m_pending_status |= STATUS_VINT; |
| 415 | 441 | } |
| 416 | 442 | |
| 417 | update_palette(); | |
| 443 | /* Draw borders */ | |
| 444 | m_lborder_timer->adjust( m_screen->time_until_pos( vpos, SEGA315_5124_LBORDER_START ), vpos ); | |
| 445 | m_rborder_timer->adjust( m_screen->time_until_pos( vpos, SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH + 256 ), vpos ); | |
| 418 | 446 | |
| 419 | /* Draw left border */ | |
| 420 | rec.min_x = SEGA315_5124_LBORDER_START; | |
| 421 | rec.max_x = SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH - 1; | |
| 422 | m_tmpbitmap.fill(m_palette->pen(m_current_palette[BACKDROP_COLOR]), rec); | |
| 423 | m_y1_bitmap.fill(1, rec); | |
| 424 | ||
| 425 | /* Draw right border */ | |
| 426 | rec.min_x = SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH + 256; | |
| 427 | rec.max_x = rec.min_x + SEGA315_5124_RBORDER_WIDTH - 1; | |
| 428 | m_tmpbitmap.fill(m_palette->pen(m_current_palette[BACKDROP_COLOR]), rec); | |
| 429 | m_y1_bitmap.fill(1, rec); | |
| 430 | ||
| 431 | 447 | /* Draw middle of the border */ |
| 432 | 448 | /* We need to do this through the regular drawing function so it will */ |
| 433 | 449 | /* be included in the gamegear scaling functions */ |
| 434 | draw_sc | |
| 450 | m_draw_timer->adjust( m_screen->time_until_pos( vpos, m_draw_time ), vpos_limit - m_frame_timing[ACTIVE_DISPLAY_V] ); | |
| 435 | 451 | return; |
| 436 | 452 | } |
| 437 | 453 | |
| r31075 | r31076 | |
| 449 | 465 | if (m_line_counter == 0x00) |
| 450 | 466 | { |
| 451 | 467 | m_line_counter = m_reg[0x0a]; |
| 452 | m_ | |
| 468 | m_hint_timer->adjust( m_screen->time_until_pos( vpos, HINT_HPOS ) ); | |
| 453 | 469 | m_pending_status |= STATUS_HINT; |
| 454 | 470 | } |
| 455 | 471 | else |
| r31075 | r31076 | |
| 457 | 473 | m_line_counter--; |
| 458 | 474 | } |
| 459 | 475 | |
| 460 | update_palette(); | |
| 476 | /* Draw borders */ | |
| 477 | m_lborder_timer->adjust( m_screen->time_until_pos( vpos, SEGA315_5124_LBORDER_START ), vpos ); | |
| 478 | m_rborder_timer->adjust( m_screen->time_until_pos( vpos, SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH + 256 ), vpos ); | |
| 461 | 479 | |
| 462 | /* Draw left border */ | |
| 463 | rec.min_x = SEGA315_5124_LBORDER_START; | |
| 464 | rec.max_x = SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH - 1; | |
| 465 | m_tmpbitmap.fill(m_palette->pen(m_current_palette[BACKDROP_COLOR]), rec); | |
| 466 | m_y1_bitmap.fill(1, rec); | |
| 467 | ||
| 468 | /* Draw right border */ | |
| 469 | rec.min_x = SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH + 256; | |
| 470 | rec.max_x = rec.min_x + SEGA315_5124_RBORDER_WIDTH - 1; | |
| 471 | m_tmpbitmap.fill(m_palette->pen(m_current_palette[BACKDROP_COLOR]), rec); | |
| 472 | m_y1_bitmap.fill(1, rec); | |
| 473 | ||
| 480 | /* Draw active display */ | |
| 474 | 481 | select_sprites( vpos - vpos_limit ); |
| 475 | if ( m_draw_time > 0 ) | |
| 476 | { | |
| 477 | m_draw_timer->adjust( m_screen->time_until_pos( vpos, m_draw_time ), vpos_limit ); | |
| 478 | } | |
| 479 | else | |
| 480 | { | |
| 481 | draw_scanline( SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH, vpos_limit, vpos - vpos_limit ); | |
| 482 | } | |
| 482 | m_draw_timer->adjust( m_screen->time_until_pos( vpos, m_draw_time ), vpos_limit ); | |
| 483 | 483 | return; |
| 484 | 484 | } |
| 485 | 485 | |
| r31075 | r31076 | |
| 489 | 489 | if (vpos >= vpos_limit) |
| 490 | 490 | { |
| 491 | 491 | m_line_counter = m_reg[0x0a]; |
| 492 | update_palette(); | |
| 493 | 492 | |
| 494 | /* Draw left border */ | |
| 495 | rec.min_x = SEGA315_5124_LBORDER_START; | |
| 496 | rec.max_x = SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH - 1; | |
| 497 | m_tmpbitmap.fill(m_palette->pen(m_current_palette[BACKDROP_COLOR]), rec); | |
| 498 | m_y1_bitmap.fill(1, rec); | |
| 493 | /* Check if we're on the last line of the top border */ | |
| 494 | if (vpos == vpos_limit + m_frame_timing[TOP_BORDER] - 1) | |
| 495 | { | |
| 496 | m_nmi_timer->adjust( m_screen->time_until_pos( vpos, NMI_HPOS ) ); | |
| 497 | } | |
| 499 | 498 | |
| 500 | /* Draw right border */ | |
| 501 | rec.min_x = SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH + 256; | |
| 502 | rec.max_x = rec.min_x + SEGA315_5124_RBORDER_WIDTH - 1; | |
| 503 | m_tmpbitmap.fill(m_palette->pen(m_current_palette[BACKDROP_COLOR]), rec); | |
| 504 | m_y1_bitmap.fill(1, rec); | |
| 499 | /* Draw borders */ | |
| 500 | m_lborder_timer->adjust( m_screen->time_until_pos( vpos, SEGA315_5124_LBORDER_START ), vpos ); | |
| 501 | m_rborder_timer->adjust( m_screen->time_until_pos( vpos, SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH + 256 ), vpos ); | |
| 505 | 502 | |
| 506 | 503 | /* Draw middle of the border */ |
| 507 | 504 | /* We need to do this through the regular drawing function so it will */ |
| 508 | 505 | /* be included in the gamegear scaling functions */ |
| 509 | 506 | select_sprites( vpos - (vpos_limit + m_frame_timing[TOP_BORDER]) ); |
| 510 | draw_sc | |
| 507 | m_draw_timer->adjust( m_screen->time_until_pos( vpos, m_draw_time ), vpos_limit + m_frame_timing[TOP_BORDER] ); | |
| 511 | 508 | return; |
| 512 | 509 | } |
| 513 | 510 | |
| r31075 | r31076 | |
| 543 | 540 | |
| 544 | 541 | void sega315_5124_device::check_pending_flags() |
| 545 | 542 | { |
| 546 | const attotime current_time = machine().time(); | |
| 547 | 543 | int hpos; |
| 548 | 544 | |
| 549 | if ( | |
| 545 | if (!m_pending_status) | |
| 550 | 546 | { |
| 551 | | |
| 547 | return; | |
| 552 | 548 | } |
| 553 | else | |
| 549 | ||
| 550 | hpos = m_screen->hpos(); | |
| 551 | if (hpos < DISPLAY_CB_HPOS || m_display_timer->remaining() == attotime::zero) | |
| 554 | 552 | { |
| 555 | 553 | hpos = m_screen->width(); |
| 556 | m_line_end_time = current_time + m_screen->time_until_pos(m_screen->vpos(), hpos); | |
| 557 | 554 | } |
| 558 | 555 | |
| 559 | 556 | if ((m_pending_status & STATUS_HINT) && hpos >= HINT_HPOS) |
| 560 | 557 | { |
| 561 | 558 | m_pending_status &= ~STATUS_HINT; |
| 562 | m_status |= STATUS_HINT; | |
| 559 | m_status |= STATUS_HINT; // fake flag. | |
| 563 | 560 | } |
| 564 | 561 | if ((m_pending_status & STATUS_VINT) && hpos >= VINT_FLAG_HPOS) |
| 565 | 562 | { |
| r31075 | r31076 | |
| 688 | 685 | // So here, where the setting is done, the irq_state needs to be cleared. |
| 689 | 686 | // |
| 690 | 687 | // For VINT disabling through register 01: |
| 691 | // When running eagles5 on the sms | |
| 688 | // When running eagles5 on the smskr driver the irq_state is 1 because of some | |
| 692 | 689 | // previos HINTs that occured. eagles5 sets register 01 to 0x02 and expects |
| 693 | 690 | // the irq state to be cleared after that. |
| 694 | 691 | // The following bit of code takes care of that. |
| 695 | 692 | // |
| 696 | if ( ( (m_status & STATUS_HINT) && !(m_reg[0x00] & 0x10) ) || | |
| 697 | ( (m_status & STATUS_VINT) && !(m_reg[0x01] & 0x20) ) ) | |
| 693 | if ( ( reg_num == 0 && !(m_reg[0x00] & 0x10) ) || | |
| 694 | ( reg_num == 1 && !(m_reg[0x01] & 0x20) ) ) | |
| 698 | 695 | { |
| 699 | 696 | if (m_irq_state == 1) |
| 700 | 697 | { |
| r31075 | r31076 | |
| 956 | 953 | bool sprite_col_occurred = false; |
| 957 | 954 | int sprite_col_x = m_screen->width(); |
| 958 | 955 | |
| 959 | /* Draw sprite layer */ | |
| 960 | ||
| 961 | /* Check if display is disabled */ | |
| 962 | 956 | if (m_display_disabled) |
| 963 | 957 | return; |
| 964 | 958 | |
| 965 | 959 | memset(m_collision_buffer, 0, SEGA315_5124_WIDTH); |
| 966 | 960 | |
| 961 | /* Draw sprite layer */ | |
| 967 | 962 | for (int sprite_buffer_index = m_sprite_count - 1; sprite_buffer_index >= 0; sprite_buffer_index--) |
| 968 | 963 | { |
| 969 | 964 | int sprite_index = m_selected_sprite[sprite_buffer_index]; |
| r31075 | r31076 | |
| 1115 | 1110 | int sprite_col_x = m_screen->width(); |
| 1116 | 1111 | UINT16 sprite_pattern_base = ((m_reg[0x06] & 0x07) << 11); |
| 1117 | 1112 | |
| 1118 | /* Draw sprite layer */ | |
| 1119 | ||
| 1120 | /* Check if display is disabled */ | |
| 1121 | 1113 | if (m_display_disabled) |
| 1122 | 1114 | return; |
| 1123 | 1115 | |
| 1124 | 1116 | memset(m_collision_buffer, 0, SEGA315_5124_WIDTH); |
| 1125 | 1117 | |
| 1118 | /* Draw sprite layer */ | |
| 1126 | 1119 | for (int sprite_buffer_index = m_sprite_count - 1; sprite_buffer_index >= 0; sprite_buffer_index--) |
| 1127 | 1120 | { |
| 1128 | 1121 | int sprite_index = m_selected_sprite[sprite_buffer_index]; |
| r31075 | r31076 | |
| 1306 | 1299 | UINT16 name_table_base, color_base, pattern_base; |
| 1307 | 1300 | int pattern_mask, color_mask, pattern_offset; |
| 1308 | 1301 | |
| 1309 | /* Draw background layer */ | |
| 1310 | 1302 | name_table_base = ((m_reg[0x02] & 0x0f) << 10) + ((line >> 3) * 32); |
| 1311 | 1303 | color_base = ((m_reg[0x03] & 0x80) << 6); |
| 1312 | 1304 | color_mask = ((m_reg[0x03] & 0x7f) << 3) | 0x07; |
| r31075 | r31076 | |
| 1314 | 1306 | pattern_mask = ((m_reg[0x04] & 0x03) << 8) | 0xff; |
| 1315 | 1307 | pattern_offset = (line & 0xc0) << 2; |
| 1316 | 1308 | |
| 1309 | /* Draw background layer */ | |
| 1317 | 1310 | for (tile_column = 0; tile_column < 32; tile_column++) |
| 1318 | 1311 | { |
| 1319 | 1312 | UINT8 name = space().read_byte( name_table_base + tile_column ); |
| r31075 | r31076 | |
| 1355 | 1348 | int pixel_x, pixel_plot_x; |
| 1356 | 1349 | UINT16 name_base, color_base, pattern_base; |
| 1357 | 1350 | |
| 1358 | /* Draw background layer */ | |
| 1359 | 1351 | name_base = ((m_reg[0x02] & 0x0f) << 10) + ((line >> 3) * 32); |
| 1360 | 1352 | color_base = ((m_reg[0x03] << 6) & (VRAM_SIZE - 1)); |
| 1361 | 1353 | pattern_base = ((m_reg[0x04] << 11) & (VRAM_SIZE - 1)); |
| 1362 | 1354 | |
| 1355 | /* Draw background layer */ | |
| 1363 | 1356 | for (tile_column = 0; tile_column < 32; tile_column++) |
| 1364 | 1357 | { |
| 1365 | 1358 | UINT8 name = space().read_byte( name_base + tile_column ); |
| r31075 | r31076 | |
| 1750 | 1743 | void sega315_5124_device::stop_timers() |
| 1751 | 1744 | { |
| 1752 | 1745 | m_display_timer->adjust(attotime::never); |
| 1753 | m_check_hint_timer->adjust(attotime::never); | |
| 1754 | m_check_vint_timer->adjust(attotime::never); | |
| 1746 | m_hint_timer->adjust(attotime::never); | |
| 1747 | m_vint_timer->adjust(attotime::never); | |
| 1748 | m_nmi_timer->adjust(attotime::never); | |
| 1755 | 1749 | m_draw_timer->adjust(attotime::never); |
| 1750 | m_lborder_timer->adjust(attotime::never); | |
| 1751 | m_rborder_timer->adjust(attotime::never); | |
| 1756 | 1752 | } |
| 1757 | 1753 | |
| 1758 | 1754 | |
| r31075 | r31076 | |
| 1798 | 1794 | m_display_timer = timer_alloc(TIMER_LINE); |
| 1799 | 1795 | m_display_timer->adjust(m_screen->time_until_pos(0, DISPLAY_CB_HPOS), 0, m_screen->scan_period()); |
| 1800 | 1796 | m_draw_timer = timer_alloc(TIMER_DRAW); |
| 1801 | m_check_hint_timer = timer_alloc(TIMER_CHECK_HINT); | |
| 1802 | m_check_vint_timer = timer_alloc(TIMER_CHECK_VINT); | |
| 1797 | m_lborder_timer = timer_alloc(TIMER_LBORDER); | |
| 1798 | m_rborder_timer = timer_alloc(TIMER_RBORDER); | |
| 1799 | m_hint_timer = timer_alloc(TIMER_HINT); | |
| 1800 | m_vint_timer = timer_alloc(TIMER_VINT); | |
| 1801 | m_nmi_timer = timer_alloc(TIMER_NMI); | |
| 1803 | 1802 | |
| 1804 | 1803 | save_item(NAME(m_status)); |
| 1805 | 1804 | save_item(NAME(m_pending_status)); |
| r31075 | r31076 | |
| 1826 | 1825 | save_item(NAME(m_tmpbitmap)); |
| 1827 | 1826 | save_item(NAME(m_y1_bitmap)); |
| 1828 | 1827 | save_item(NAME(m_draw_time)); |
| 1829 | save_item(NAME(m_line_end_time)); | |
| 1830 | 1828 | save_item(NAME(m_sprite_base)); |
| 1831 | 1829 | save_item(NAME(m_selected_sprite)); |
| 1832 | 1830 | save_item(NAME(m_sprite_count)); |
| r31075 | r31076 | |
| 1865 | 1863 | m_line_counter = 0; |
| 1866 | 1864 | m_hcounter = 0; |
| 1867 | 1865 | m_draw_time = DRAW_TIME_SMS; |
| 1868 | m_line_end_time = machine().time() + m_screen->time_until_pos(m_screen->vpos(), m_screen->width()); | |
| 1869 | 1866 | |
| 1870 | 1867 | for (i = 0; i < 0x20; i++) |
| 1871 | 1868 | m_current_palette[i] = 0; |
| r31075 | r31076 | |
|---|---|---|
| 17 | 17 | #define SEGA315_5124_WIDTH 342 /* 342 pixels */ |
| 18 | 18 | #define SEGA315_5124_HEIGHT_NTSC 262 /* 262 lines */ |
| 19 | 19 | #define SEGA315_5124_HEIGHT_PAL 313 /* 313 lines */ |
| 20 | #define SEGA315_5124_LBORDER_START ( | |
| 20 | #define SEGA315_5124_LBORDER_START (9 + 2 + 14 + 8) | |
| 21 | 21 | #define SEGA315_5124_LBORDER_WIDTH 13 /* 13 pixels */ |
| 22 | 22 | #define SEGA315_5124_RBORDER_WIDTH 15 /* 15 pixels */ |
| 23 | 23 | #define SEGA315_5124_TBORDER_START (3 + 13) |
| r31075 | r31076 | |
| 129 | 129 | int m_vdp_mode; /* Current mode of the VDP: 0,1,2,3,4 */ |
| 130 | 130 | int m_y_pixels; /* 192, 224, 240 */ |
| 131 | 131 | int m_draw_time; |
| 132 | attotime m_line_end_time; | |
| 133 | 132 | UINT8 m_line_counter; |
| 134 | 133 | UINT8 m_hcounter; |
| 135 | 134 | memory_region *m_CRAM; /* Pointer to CRAM */ |
| r31075 | r31076 | |
| 155 | 154 | devcb_write_line m_int_cb; /* Interrupt callback function */ |
| 156 | 155 | devcb_write_line m_pause_cb; /* Pause callback function */ |
| 157 | 156 | emu_timer *m_display_timer; |
| 158 | emu_timer *m_check_hint_timer; | |
| 159 | emu_timer *m_check_vint_timer; | |
| 157 | emu_timer *m_hint_timer; | |
| 158 | emu_timer *m_vint_timer; | |
| 159 | emu_timer *m_nmi_timer; | |
| 160 | 160 | emu_timer *m_draw_timer; |
| 161 | emu_timer *m_lborder_timer; | |
| 162 | emu_timer *m_rborder_timer; | |
| 161 | 163 | |
| 162 | 164 | const address_space_config m_space_config; |
| 163 | 165 | |
| 164 | 166 | /* Timers */ |
| 165 | 167 | static const device_timer_id TIMER_LINE = 0; |
| 166 | 168 | static const device_timer_id TIMER_DRAW = 1; |
| 167 | static const device_timer_id TIMER_CHECK_HINT = 2; | |
| 168 | static const device_timer_id TIMER_CHECK_VINT = 3; | |
| 169 | static const device_timer_id TIMER_LBORDER = 2; | |
| 170 | static const device_timer_id TIMER_RBORDER = 3; | |
| 171 | static const device_timer_id TIMER_HINT = 4; | |
| 172 | static const device_timer_id TIMER_VINT = 5; | |
| 173 | static const device_timer_id TIMER_NMI = 6; | |
| 169 | 174 | |
| 170 | 175 | required_device<palette_device> m_palette; |
| 171 | 176 | }; |
| Previous | 199869 Revisions | Next |