trunk/src/emu/video/315_5124.c
| r21804 | r21805 | |
| 54 | 54 | #define STATUS_SPRCOL 0x20 /* Object collision flag */ |
| 55 | 55 | #define STATUS_HINT 0x02 /* Pending horizontal interrupt flag */ |
| 56 | 56 | |
| 57 | | #define VINT_HPOS 23 |
| 58 | | #define HINT_HPOS 23 |
| 59 | | #define VCOUNT_CHANGE_HPOS 22 |
| 60 | | #define VINT_FLAG_HPOS 7 |
| 61 | | #define SPROVR_HPOS 6 |
| 62 | | #define SPRCOL_BASEHPOS 42 |
| 63 | | #define DISPLAY_CB_HPOS 5 /* fix X-Scroll latchtime (Flubba's VDPTest) */ |
| 57 | #define VINT_HPOS 24 |
| 58 | #define VINT_FLAG_HPOS 23 |
| 59 | #define HINT_HPOS 25 |
| 60 | #define VCOUNT_CHANGE_HPOS 23 |
| 61 | #define SPROVR_HPOS 23 |
| 62 | #define SPRCOL_BASEHPOS 59 |
| 63 | #define DISPLAY_CB_HPOS 6 /* fix X-Scroll latchtime (Flubba's VDPTest) */ |
| 64 | 64 | |
| 65 | 65 | #define DRAW_TIME_GG 86 /* 1 + 2 + 14 +8 + 96/2 */ |
| 66 | 66 | #define DRAW_TIME_SMS 0 |
| r21804 | r21805 | |
| 294 | 294 | draw_scanline( SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH, param, m_screen->vpos() - param ); |
| 295 | 295 | break; |
| 296 | 296 | |
| 297 | | case TIMER_SET_STATUS_VINT: |
| 298 | | m_status |= STATUS_VINT; |
| 299 | | break; |
| 300 | | |
| 301 | | case TIMER_SET_STATUS_SPROVR: |
| 302 | | m_status |= STATUS_SPROVR; |
| 303 | | break; |
| 304 | | |
| 305 | | case TIMER_SET_STATUS_SPRCOL: |
| 306 | | m_status |= STATUS_SPRCOL; |
| 307 | | break; |
| 308 | | |
| 309 | 297 | case TIMER_CHECK_HINT: |
| 310 | | if (m_line_counter == 0x00) |
| 298 | if ((m_pending_status & STATUS_HINT) || (m_status & STATUS_HINT)) |
| 311 | 299 | { |
| 312 | | m_line_counter = m_reg[0x0a]; |
| 313 | | m_status |= STATUS_HINT; |
| 314 | | } |
| 315 | | else |
| 316 | | { |
| 317 | | m_line_counter--; |
| 318 | | } |
| 300 | if ((m_reg[0x00] & 0x10)) |
| 301 | { |
| 302 | m_irq_state = 1; |
| 319 | 303 | |
| 320 | | if ((m_status & STATUS_HINT) && (m_reg[0x00] & 0x10)) |
| 321 | | { |
| 322 | | m_irq_state = 1; |
| 323 | | |
| 324 | | if ( !m_cb_int.isnull() ) |
| 325 | | m_cb_int(ASSERT_LINE); |
| 304 | if ( !m_cb_int.isnull() ) |
| 305 | m_cb_int(ASSERT_LINE); |
| 306 | } |
| 326 | 307 | } |
| 327 | 308 | break; |
| 328 | 309 | |
| 329 | 310 | case TIMER_CHECK_VINT: |
| 330 | | if ((m_status & STATUS_VINT) && (m_reg[0x01] & 0x20)) |
| 311 | if ((m_pending_status & STATUS_VINT) || (m_status & STATUS_VINT)) |
| 331 | 312 | { |
| 332 | | m_irq_state = 1; |
| 313 | if ((m_reg[0x01] & 0x20)) |
| 314 | { |
| 315 | m_irq_state = 1; |
| 333 | 316 | |
| 334 | | if ( !m_cb_int.isnull() ) |
| 335 | | m_cb_int(ASSERT_LINE); |
| 317 | if ( !m_cb_int.isnull() ) |
| 318 | m_cb_int(ASSERT_LINE); |
| 319 | } |
| 336 | 320 | } |
| 337 | 321 | break; |
| 338 | 322 | } |
| r21804 | r21805 | |
| 349 | 333 | |
| 350 | 334 | rec.min_y = rec.max_y = vpos; |
| 351 | 335 | |
| 336 | /* Activate flags that were pending until the end of previous line. */ |
| 337 | check_pending_flags(m_screen->width()); |
| 338 | |
| 352 | 339 | /* Check if we're on the last line of a frame */ |
| 353 | 340 | if (vpos == vpos_limit - 1) |
| 354 | 341 | { |
| r21804 | r21805 | |
| 375 | 362 | { |
| 376 | 363 | if (vpos == vpos_limit) |
| 377 | 364 | { |
| 378 | | m_check_hint_timer->adjust( m_screen->time_until_pos( vpos, HINT_HPOS ) ); |
| 365 | if (m_line_counter == 0x00) |
| 366 | { |
| 367 | m_line_counter = m_reg[0x0a]; |
| 368 | m_check_hint_timer->adjust( m_screen->time_until_pos( vpos, HINT_HPOS ) ); |
| 369 | m_pending_status |= STATUS_HINT; |
| 370 | } |
| 371 | else |
| 372 | { |
| 373 | m_line_counter--; |
| 374 | } |
| 379 | 375 | } |
| 380 | 376 | else |
| 381 | 377 | { |
| r21804 | r21805 | |
| 384 | 380 | |
| 385 | 381 | if (vpos == vpos_limit + 1) |
| 386 | 382 | { |
| 387 | | m_set_status_vint_timer->adjust( m_screen->time_until_pos( vpos, VINT_FLAG_HPOS ) ); |
| 388 | 383 | m_check_vint_timer->adjust( m_screen->time_until_pos( vpos, VINT_HPOS ) ); |
| 384 | m_pending_status |= STATUS_VINT; |
| 389 | 385 | } |
| 390 | 386 | |
| 391 | 387 | update_palette(); |
| r21804 | r21805 | |
| 419 | 415 | m_reg9copy = m_reg[0x09]; |
| 420 | 416 | } |
| 421 | 417 | |
| 422 | | m_check_hint_timer->adjust( m_screen->time_until_pos( vpos, HINT_HPOS ) ); |
| 418 | if (m_line_counter == 0x00) |
| 419 | { |
| 420 | m_line_counter = m_reg[0x0a]; |
| 421 | m_check_hint_timer->adjust( m_screen->time_until_pos( vpos, HINT_HPOS ) ); |
| 422 | m_pending_status |= STATUS_HINT; |
| 423 | } |
| 424 | else |
| 425 | { |
| 426 | m_line_counter--; |
| 427 | } |
| 423 | 428 | |
| 424 | 429 | update_palette(); |
| 425 | 430 | |
| r21804 | r21805 | |
| 488 | 493 | /* to the address register when in the middle of doing a command. */ |
| 489 | 494 | /* Cosmic Spacehead needs this, among others */ |
| 490 | 495 | /* Clear pending write flag */ |
| 491 | | m_pending = 0; |
| 496 | m_pending_reg_write = 0; |
| 492 | 497 | |
| 493 | 498 | /* Return read buffer contents */ |
| 494 | 499 | temp = m_buffer; |
| r21804 | r21805 | |
| 505 | 510 | } |
| 506 | 511 | |
| 507 | 512 | |
| 513 | void sega315_5124_device::check_pending_flags( int hpos ) |
| 514 | { |
| 515 | if ((m_pending_status & STATUS_HINT) && hpos >= HINT_HPOS) |
| 516 | { |
| 517 | m_pending_status &= ~STATUS_HINT; |
| 518 | m_status |= STATUS_HINT; |
| 519 | } |
| 520 | if ((m_pending_status & STATUS_VINT) && hpos >= VINT_FLAG_HPOS) |
| 521 | { |
| 522 | m_pending_status &= ~STATUS_VINT; |
| 523 | m_status |= STATUS_VINT; |
| 524 | } |
| 525 | if ((m_pending_status & STATUS_SPROVR) && hpos >= SPROVR_HPOS) |
| 526 | { |
| 527 | m_pending_status &= ~STATUS_SPROVR; |
| 528 | m_status |= STATUS_SPROVR; |
| 529 | } |
| 530 | if ((m_pending_status & STATUS_SPRCOL) && hpos >= m_pending_sprcol_x) |
| 531 | { |
| 532 | m_pending_status &= ~STATUS_SPRCOL; |
| 533 | m_status |= STATUS_SPRCOL; |
| 534 | m_pending_sprcol_x = 0; |
| 535 | } |
| 536 | } |
| 537 | |
| 538 | |
| 508 | 539 | READ8_MEMBER( sega315_5124_device::register_read ) |
| 509 | 540 | { |
| 510 | | UINT8 temp = m_status; |
| 541 | UINT8 temp; |
| 511 | 542 | |
| 543 | check_pending_flags(m_screen->hpos()); |
| 544 | temp = m_status; |
| 545 | |
| 512 | 546 | if ( !space.debugger_access() ) |
| 513 | 547 | { |
| 514 | 548 | /* Clear pending write flag */ |
| 515 | | m_pending = 0; |
| 549 | m_pending_reg_write = 0; |
| 516 | 550 | |
| 517 | 551 | m_status &= ~(STATUS_VINT | STATUS_SPROVR | STATUS_SPRCOL | STATUS_HINT); |
| 518 | 552 | |
| r21804 | r21805 | |
| 536 | 570 | /* to the address register when in the middle of doing a command. */ |
| 537 | 571 | /* Cosmic Spacehead needs this, among others */ |
| 538 | 572 | /* Clear pending write flag */ |
| 539 | | m_pending = 0; |
| 573 | m_pending_reg_write = 0; |
| 540 | 574 | |
| 541 | 575 | switch(m_addrmode) |
| 542 | 576 | { |
| r21804 | r21805 | |
| 567 | 601 | { |
| 568 | 602 | int reg_num; |
| 569 | 603 | |
| 570 | | if (m_pending == 0) |
| 604 | check_pending_flags(m_screen->hpos()); |
| 605 | |
| 606 | if (m_pending_reg_write == 0) |
| 571 | 607 | { |
| 572 | 608 | m_addr = (m_addr & 0xff00) | data; |
| 573 | | m_pending = 1; |
| 609 | m_pending_reg_write = 1; |
| 574 | 610 | } |
| 575 | 611 | else |
| 576 | 612 | { |
| 577 | 613 | /* Clear pending write flag */ |
| 578 | | m_pending = 0; |
| 614 | m_pending_reg_write = 0; |
| 579 | 615 | |
| 580 | 616 | m_addrmode = (data >> 6) & 0x03; |
| 581 | 617 | m_addr = (data << 8) | (m_addr & 0xff); |
| r21804 | r21805 | |
| 599 | 635 | if (reg_num == 0 || reg_num == 1) |
| 600 | 636 | set_display_settings(); |
| 601 | 637 | |
| 602 | | if (reg_num == 1) |
| 638 | if ( ( reg_num == 0 && (m_status & STATUS_HINT) ) || |
| 639 | ( reg_num == 1 && (m_status & STATUS_VINT) ) ) |
| 603 | 640 | { |
| 604 | | m_check_vint_timer->adjust( m_screen->time_until_pos( m_screen->vpos(), VINT_HPOS) ); |
| 605 | | |
| 641 | // For HINT disabling through register 00: |
| 642 | // "Line IRQ VCount" test, of Flubba's VDPTest ROM, disables HINT to wait |
| 643 | // for next VINT, but HINT occurs when the operation is about to execute. |
| 644 | // So here, where the setting is done, the irq_state needs to be cleared. |
| 606 | 645 | // |
| 607 | | // When running eagles5 on the ssm2kr driver the irq_state is 1 because of some |
| 646 | // For VINT disabling through register 01: |
| 647 | // When running eagles5 on the sms2kr driver the irq_state is 1 because of some |
| 608 | 648 | // previos HINTs that occured. eagles5 sets register 01 to 0x02 and expects |
| 609 | 649 | // the irq state to be cleared after that. |
| 610 | 650 | // The following bit of code takes care of that. |
| 611 | 651 | // |
| 612 | | if ((m_status & STATUS_VINT) && !(m_reg[0x01] & 0x20)) |
| 652 | if ( ( (m_status & STATUS_HINT) && !(m_reg[0x00] & 0x10) ) || |
| 653 | ( (m_status & STATUS_VINT) && !(m_reg[0x01] & 0x20) ) ) |
| 613 | 654 | { |
| 614 | 655 | if (m_irq_state == 1) |
| 615 | 656 | { |
| r21804 | r21805 | |
| 621 | 662 | } |
| 622 | 663 | } |
| 623 | 664 | } |
| 665 | else |
| 666 | { |
| 667 | // For register 01 and VINT enabling: |
| 668 | // Assert the IRQ line for the scoreboard of robocop3, |
| 669 | // on the sms/smspal driver, be displayed correctly. |
| 670 | // |
| 671 | // Assume the same behavior for reg0+HINT. |
| 672 | // |
| 673 | m_irq_state = 1; |
| 624 | 674 | |
| 675 | if ( !m_cb_int.isnull() ) |
| 676 | m_cb_int(ASSERT_LINE); |
| 677 | } |
| 625 | 678 | } |
| 626 | 679 | m_addrmode = 0; |
| 627 | 680 | break; |
| r21804 | r21805 | |
| 842 | 895 | |
| 843 | 896 | if (line >= 0 && line < m_frame_timing[ACTIVE_DISPLAY_V]) |
| 844 | 897 | { |
| 845 | | m_set_status_sprovr_timer->adjust( m_screen->time_until_pos( pixel_plot_y + line, SPROVR_HPOS ) ); |
| 898 | m_pending_status |= STATUS_SPROVR; |
| 846 | 899 | } |
| 847 | 900 | } |
| 848 | 901 | } |
| r21804 | r21805 | |
| 999 | 1052 | } |
| 1000 | 1053 | if (sprite_col_occurred) |
| 1001 | 1054 | { |
| 1002 | | m_set_status_sprcol_timer->adjust( m_screen->time_until_pos( pixel_plot_y + line, SPRCOL_BASEHPOS + sprite_col_x ) ); |
| 1055 | m_pending_status |= STATUS_SPRCOL; |
| 1056 | m_pending_sprcol_x = SPRCOL_BASEHPOS + sprite_col_x; |
| 1003 | 1057 | } |
| 1004 | 1058 | } |
| 1005 | 1059 | } |
| r21804 | r21805 | |
| 1188 | 1242 | } |
| 1189 | 1243 | if (sprite_col_occurred) |
| 1190 | 1244 | { |
| 1191 | | m_set_status_sprcol_timer->adjust( m_screen->time_until_pos( pixel_plot_y + line, SPRCOL_BASEHPOS + sprite_col_x ) ); |
| 1245 | m_pending_status |= STATUS_SPRCOL; |
| 1246 | m_pending_sprcol_x = SPRCOL_BASEHPOS + sprite_col_x; |
| 1192 | 1247 | } |
| 1193 | 1248 | } |
| 1194 | 1249 | } |
| r21804 | r21805 | |
| 1644 | 1699 | m_display_timer = timer_alloc(TIMER_LINE); |
| 1645 | 1700 | m_display_timer->adjust(m_screen->time_until_pos(0, DISPLAY_CB_HPOS), 0, m_screen->scan_period()); |
| 1646 | 1701 | m_draw_timer = timer_alloc(TIMER_DRAW); |
| 1647 | | m_set_status_vint_timer = timer_alloc( TIMER_SET_STATUS_VINT ); |
| 1648 | | m_set_status_sprovr_timer = timer_alloc( TIMER_SET_STATUS_SPROVR ); |
| 1649 | | m_set_status_sprcol_timer = timer_alloc( TIMER_SET_STATUS_SPRCOL ); |
| 1650 | | m_check_hint_timer = timer_alloc( TIMER_CHECK_HINT ); |
| 1651 | | m_check_vint_timer = timer_alloc( TIMER_CHECK_VINT ); |
| 1702 | m_check_hint_timer = timer_alloc(TIMER_CHECK_HINT); |
| 1703 | m_check_vint_timer = timer_alloc(TIMER_CHECK_VINT); |
| 1652 | 1704 | |
| 1653 | 1705 | save_item(NAME(m_status)); |
| 1706 | save_item(NAME(m_pending_status)); |
| 1707 | save_item(NAME(m_pending_sprcol_x)); |
| 1654 | 1708 | save_item(NAME(m_reg9copy)); |
| 1655 | 1709 | save_item(NAME(m_addrmode)); |
| 1656 | 1710 | save_item(NAME(m_addr)); |
| 1657 | 1711 | save_item(NAME(m_cram_mask)); |
| 1658 | 1712 | save_item(NAME(m_cram_dirty)); |
| 1659 | | save_item(NAME(m_pending)); |
| 1713 | save_item(NAME(m_pending_reg_write)); |
| 1660 | 1714 | save_item(NAME(m_buffer)); |
| 1661 | 1715 | save_item(NAME(m_sega315_5124_compatibility_mode)); |
| 1662 | 1716 | save_item(NAME(m_irq_state)); |
| r21804 | r21805 | |
| 1686 | 1740 | m_reg[0x0a] = 0xff; |
| 1687 | 1741 | |
| 1688 | 1742 | m_status = 0; |
| 1743 | m_pending_status = 0; |
| 1744 | m_pending_sprcol_x = 0; |
| 1745 | m_pending_reg_write = 0; |
| 1689 | 1746 | m_reg9copy = 0; |
| 1690 | 1747 | m_addrmode = 0; |
| 1691 | 1748 | m_addr = 0; |
| 1692 | 1749 | m_sega315_5124_compatibility_mode = false; |
| 1693 | 1750 | m_cram_mask = m_cram_size - 1; |
| 1694 | 1751 | m_cram_dirty = 1; |
| 1695 | | m_pending = 0; |
| 1696 | 1752 | m_buffer = 0; |
| 1697 | 1753 | m_irq_state = 0; |
| 1698 | 1754 | m_line_counter = 0; |
trunk/src/emu/video/315_5124.h
| r21804 | r21805 | |
| 103 | 103 | void draw_scanline_mode2( int *line_buffer, int line ); |
| 104 | 104 | void draw_scanline_mode0( int *line_buffer, int line ); |
| 105 | 105 | void select_sprites( int pixel_plot_y, int line ); |
| 106 | void check_pending_flags( int hpos ); |
| 106 | 107 | |
| 107 | 108 | // device-level overrides |
| 108 | 109 | virtual void device_config_complete(); |
| r21804 | r21805 | |
| 114 | 115 | |
| 115 | 116 | UINT8 m_reg[16]; /* All the registers */ |
| 116 | 117 | UINT8 m_status; /* Status register */ |
| 118 | UINT8 m_pending_status; /* Pending status flags */ |
| 117 | 119 | UINT8 m_reg9copy; /* Internal copy of register 9 */ |
| 118 | 120 | UINT8 m_addrmode; /* Type of VDP action */ |
| 119 | 121 | UINT16 m_addr; /* Contents of internal VDP address register */ |
| 120 | 122 | UINT8 m_cram_size; /* CRAM size */ |
| 121 | 123 | UINT8 m_cram_mask; /* Mask to switch between SMS and GG CRAM sizes */ |
| 122 | 124 | int m_cram_dirty; /* Have there been any changes to the CRAM area */ |
| 123 | | int m_pending; |
| 125 | int m_pending_reg_write; |
| 126 | int m_pending_sprcol_x; |
| 124 | 127 | UINT8 m_buffer; |
| 125 | 128 | bool m_sega315_5124_compatibility_mode; /* Shrunk SMS screen on GG lcd mode flag */ |
| 126 | 129 | int m_irq_state; /* The status of the IRQ line of the VDP */ |
| r21804 | r21805 | |
| 132 | 135 | memory_region *m_CRAM; /* Pointer to CRAM */ |
| 133 | 136 | const UINT8 *m_frame_timing; |
| 134 | 137 | bitmap_rgb32 m_tmpbitmap; |
| 135 | | bitmap_ind8 m_y1_bitmap; |
| 138 | bitmap_ind8 m_y1_bitmap; |
| 136 | 139 | UINT8 m_collision_buffer[SEGA315_5124_WIDTH]; |
| 137 | 140 | UINT8 m_palette_offset; |
| 138 | 141 | bool m_supports_224_240; |
| r21804 | r21805 | |
| 150 | 153 | devcb_resolved_write_line m_cb_int; |
| 151 | 154 | devcb_resolved_write_line m_cb_pause; |
| 152 | 155 | emu_timer *m_display_timer; |
| 153 | | emu_timer *m_set_status_vint_timer; |
| 154 | | emu_timer *m_set_status_sprovr_timer; |
| 155 | | emu_timer *m_set_status_sprcol_timer; |
| 156 | 156 | emu_timer *m_check_hint_timer; |
| 157 | 157 | emu_timer *m_check_vint_timer; |
| 158 | 158 | emu_timer *m_draw_timer; |
| r21804 | r21805 | |
| 162 | 162 | |
| 163 | 163 | /* Timers */ |
| 164 | 164 | static const device_timer_id TIMER_LINE = 0; |
| 165 | | static const device_timer_id TIMER_SET_STATUS_VINT = 1; |
| 166 | | static const device_timer_id TIMER_SET_STATUS_SPROVR = 2; |
| 167 | | static const device_timer_id TIMER_CHECK_HINT = 3; |
| 168 | | static const device_timer_id TIMER_CHECK_VINT = 4; |
| 169 | | static const device_timer_id TIMER_SET_STATUS_SPRCOL = 5; |
| 170 | | static const device_timer_id TIMER_DRAW = 6; |
| 165 | static const device_timer_id TIMER_DRAW = 1; |
| 166 | static const device_timer_id TIMER_CHECK_HINT = 2; |
| 167 | static const device_timer_id TIMER_CHECK_VINT = 3; |
| 171 | 168 | }; |
| 172 | 169 | |
| 173 | 170 | |
trunk/src/mess/machine/sms.c
| r21804 | r21805 | |
| 391 | 391 | |
| 392 | 392 | UINT8 sms_state::sms_vdp_hcount() |
| 393 | 393 | { |
| 394 | | UINT8 tmp; |
| 395 | | int hpos = m_main_scr->hpos(); |
| 394 | UINT64 cycles_per_line; |
| 395 | attotime line_remaining_time; |
| 396 | UINT64 line_remaining_cycles; |
| 397 | UINT64 line_elapsed_cycles; |
| 396 | 398 | |
| 397 | | /* alternative method: pass HCounter test, but some others fail */ |
| 398 | | //int hpos_tmp = hpos; |
| 399 | | //if ((hpos + 2) % 6 == 0) hpos_tmp--; |
| 400 | | //tmp = ((hpos_tmp - 46) >> 1) & 0xff; |
| 399 | /* Calculate amount of CPU cycles according to screen references. |
| 400 | If some day the screen become always synced to the CPU, in the |
| 401 | proportion of their speeds, this may be replaced by the screen |
| 402 | hpos position only and the function be moved to the VDP file. */ |
| 403 | cycles_per_line = m_main_cpu->attotime_to_clocks(m_main_scr->scan_period()); |
| 404 | line_remaining_time = m_main_scr->time_until_pos(m_main_scr->vpos(), m_main_scr->width()); |
| 405 | line_remaining_cycles = m_main_cpu->attotime_to_clocks(line_remaining_time) % cycles_per_line; |
| 406 | line_elapsed_cycles = cycles_per_line - line_remaining_cycles; |
| 401 | 407 | |
| 402 | | UINT64 calc_cycles; |
| 403 | | attotime time_end; |
| 404 | | int vpos = m_main_scr->vpos(); |
| 405 | | int max_hpos = m_main_scr->width() - 1; |
| 408 | /* HCount equation, being hpos = VDP hclocks: "(hpos - 47) / 2" |
| 409 | Screen hpos based on CPU cycles: "cycles * width / cycles per line" |
| 410 | Do both in same line for one-step rounding only (required). */ |
| 411 | return ((line_elapsed_cycles * m_main_scr->width() / cycles_per_line) - 47) / 2; |
| 406 | 412 | |
| 407 | | if (hpos == max_hpos) |
| 408 | | time_end = attotime::zero; |
| 409 | | else |
| 410 | | time_end = m_main_scr->time_until_pos(vpos, max_hpos); |
| 411 | | calc_cycles = m_main_cpu->attotime_to_clocks(time_end); |
| 412 | | |
| 413 | | /* equation got from SMSPower forum, posted by Flubba. */ |
| 414 | | tmp = ((590 - (calc_cycles * 3)) / 4) & 0xff; |
| 415 | | |
| 416 | | //printf ("sms_vdp_hcount: hpos %3d => hcount %2X\n", hpos, tmp); |
| 417 | | return tmp; |
| 413 | /* Alternative hcount equation, restricted to the SMS clock: |
| 414 | "(590 - (line_remaining_cycles * 3)) / 4" |
| 415 | Posted by Flubba on SMSPower forum. */ |
| 418 | 416 | } |
| 419 | 417 | |
| 420 | 418 | |
| r21804 | r21805 | |
| 1927 | 1925 | // the "call $4010" without a following RET statement. That is basically |
| 1928 | 1926 | // a bug in the program code. The only way this cartridge could have run |
| 1929 | 1927 | // successfully on a real unit is if the RAM would be initialized with |
| 1930 | | // a F0 pattern on power up; F0 = RET P. |
| 1931 | | // |
| 1932 | | // alibaba and blockhol SMS cartridges rely on uninitialized RAM, |
| 1933 | | // then fill it with a F0 pattern ("RET P"), but only for consoles |
| 1934 | | // in Japan region (including KR), until confirmed on other consoles. |
| 1928 | // a F0 pattern on power up; F0 = RET P. Do that only for consoles in |
| 1929 | // Japan region (including KR), until confirmed on other consoles. |
| 1935 | 1930 | if (m_is_region_japan) |
| 1936 | 1931 | { |
| 1937 | 1932 | memset((UINT8*)m_space->get_write_ptr(0xc000), 0xf0, 0x1FFF); |