trunk/src/emu/video/315_5124.c
r22823 | r22824 | |
56 | 56 | |
57 | 57 | #define VINT_HPOS 24 |
58 | 58 | #define VINT_FLAG_HPOS 23 |
59 | | #define HINT_HPOS 25 |
| 59 | #define HINT_HPOS 26 |
60 | 60 | #define VCOUNT_CHANGE_HPOS 23 |
61 | 61 | #define SPROVR_HPOS 23 |
62 | 62 | #define SPRCOL_BASEHPOS 59 |
r22823 | r22824 | |
261 | 261 | } |
262 | 262 | |
263 | 263 | |
264 | | READ8_MEMBER( sega315_5124_device::hcount_latch_read ) |
| 264 | READ8_MEMBER( sega315_5124_device::hcount_read ) |
265 | 265 | { |
266 | 266 | return m_hcounter; |
267 | 267 | } |
268 | 268 | |
269 | 269 | |
270 | | WRITE8_MEMBER( sega315_5124_device::hcount_latch_write ) |
| 270 | void sega315_5124_device::hcount_latch_at_hpos( int hpos ) |
271 | 271 | { |
272 | | m_hcounter = data; |
| 272 | /* The emulation core returns a screen hpos that is one position ahead in comparison |
| 273 | with the expected VDP hclock value, if the same range is used (from 0 to width-1). */ |
| 274 | int hclock = hpos - 1; |
| 275 | if (hclock < 0) |
| 276 | hclock += m_screen->width(); |
| 277 | |
| 278 | /* Calculate and write the new hcount. */ |
| 279 | m_hcounter = ((hclock - 46) >> 1) & 0xff; |
273 | 280 | } |
274 | 281 | |
275 | 282 | |
r22823 | r22824 | |
440 | 447 | m_tmpbitmap.fill(machine().pens[m_current_palette[BACKDROP_COLOR]], rec); |
441 | 448 | m_y1_bitmap.fill(1, rec); |
442 | 449 | |
443 | | select_sprites( vpos_limit, vpos - vpos_limit ); |
| 450 | select_sprites( vpos - vpos_limit ); |
444 | 451 | if ( m_draw_time > 0 ) |
445 | 452 | { |
446 | 453 | m_draw_timer->adjust( m_screen->time_until_pos( vpos, m_draw_time ), vpos_limit ); |
r22823 | r22824 | |
475 | 482 | /* Draw middle of the border */ |
476 | 483 | /* We need to do this through the regular drawing function so it will */ |
477 | 484 | /* be included in the gamegear scaling functions */ |
478 | | select_sprites( vpos_limit + m_frame_timing[TOP_BORDER], vpos - (vpos_limit + m_frame_timing[TOP_BORDER]) ); |
| 485 | select_sprites( vpos - (vpos_limit + m_frame_timing[TOP_BORDER]) ); |
479 | 486 | draw_scanline( SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH, vpos_limit + m_frame_timing[TOP_BORDER], vpos - (vpos_limit + m_frame_timing[TOP_BORDER]) ); |
480 | 487 | return; |
481 | 488 | } |
r22823 | r22824 | |
807 | 814 | pixel_plot_x = (0 - (x_scroll & 0x07) + (tile_column << 3) + pixel_plot_x); |
808 | 815 | if (pixel_plot_x >= 0 && pixel_plot_x < 256) |
809 | 816 | { |
810 | | // logerror("%x %x\n", pixel_plot_x + pixel_offset_x, pixel_plot_y); |
| 817 | //logerror("%x %x\n", pixel_plot_x, line); |
811 | 818 | line_buffer[pixel_plot_x] = m_current_palette[pen_selected]; |
812 | 819 | priority_selected[pixel_plot_x] = priority_select | (pen_selected & 0x0f); |
813 | 820 | } |
r22823 | r22824 | |
816 | 823 | } |
817 | 824 | |
818 | 825 | |
819 | | void sega315_5124_device::select_sprites( int pixel_plot_y, int line ) |
| 826 | void sega315_5124_device::select_sprites( int line ) |
820 | 827 | { |
821 | 828 | int sprite_index = 0; |
822 | 829 | int max_sprites = 0; |
r22823 | r22824 | |
901 | 908 | } |
902 | 909 | |
903 | 910 | |
904 | | void sega315_5124_device::draw_sprites_mode4( int *line_buffer, int *priority_selected, int pixel_plot_y, int line ) |
| 911 | void sega315_5124_device::draw_sprites_mode4( int *line_buffer, int *priority_selected, int line ) |
905 | 912 | { |
906 | 913 | bool sprite_col_occurred = false; |
907 | | int sprite_col_x = 1000; |
| 914 | int sprite_col_x = m_screen->width(); |
908 | 915 | |
909 | 916 | /* Draw sprite layer */ |
910 | 917 | |
r22823 | r22824 | |
1059 | 1066 | } |
1060 | 1067 | |
1061 | 1068 | |
1062 | | void sega315_5124_device::draw_sprites_tms9918_mode( int *line_buffer, int pixel_plot_y, int line ) |
| 1069 | void sega315_5124_device::draw_sprites_tms9918_mode( int *line_buffer, int line ) |
1063 | 1070 | { |
1064 | 1071 | bool sprite_col_occurred = false; |
1065 | | int sprite_col_x = 1000; |
| 1072 | int sprite_col_x = m_screen->width(); |
1066 | 1073 | UINT16 sprite_pattern_base = ((m_reg[0x06] & 0x07) << 11); |
1067 | 1074 | |
1068 | 1075 | /* Draw sprite layer */ |
r22823 | r22824 | |
1355 | 1362 | } |
1356 | 1363 | if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) |
1357 | 1364 | { |
1358 | | draw_sprites_tms9918_mode( blitline_buffer, pixel_plot_y, line ); |
| 1365 | draw_sprites_tms9918_mode( blitline_buffer, line ); |
1359 | 1366 | } |
1360 | 1367 | break; |
1361 | 1368 | |
r22823 | r22824 | |
1367 | 1374 | } |
1368 | 1375 | if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) |
1369 | 1376 | { |
1370 | | draw_sprites_tms9918_mode( blitline_buffer, pixel_plot_y, line ); |
| 1377 | draw_sprites_tms9918_mode( blitline_buffer, line ); |
1371 | 1378 | } |
1372 | 1379 | break; |
1373 | 1380 | |
r22823 | r22824 | |
1380 | 1387 | } |
1381 | 1388 | if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) |
1382 | 1389 | { |
1383 | | draw_sprites_mode4( blitline_buffer, priority_selected, pixel_plot_y, line ); |
| 1390 | draw_sprites_mode4( blitline_buffer, priority_selected, line ); |
1384 | 1391 | if ( line >= 0 ) |
1385 | 1392 | { |
1386 | 1393 | /* Fill column 0 with overscan color from m_reg[0x07] */ |
r22823 | r22824 | |
1449 | 1456 | } |
1450 | 1457 | if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) |
1451 | 1458 | { |
1452 | | draw_sprites_tms9918_mode( blitline_buffer, pixel_plot_y, line ); |
| 1459 | draw_sprites_tms9918_mode( blitline_buffer, line ); |
1453 | 1460 | } |
1454 | 1461 | break; |
1455 | 1462 | |
r22823 | r22824 | |
1460 | 1467 | } |
1461 | 1468 | if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) |
1462 | 1469 | { |
1463 | | draw_sprites_tms9918_mode( blitline_buffer, pixel_plot_y, line ); |
| 1470 | draw_sprites_tms9918_mode( blitline_buffer, line ); |
1464 | 1471 | } |
1465 | 1472 | break; |
1466 | 1473 | |
r22823 | r22824 | |
1473 | 1480 | } |
1474 | 1481 | if ( line >= 0 || ( line >= -13 && m_y_pixels == 192 ) ) |
1475 | 1482 | { |
1476 | | draw_sprites_mode4( blitline_buffer, priority_selected, pixel_plot_y, line ); |
| 1483 | draw_sprites_mode4( blitline_buffer, priority_selected, line ); |
1477 | 1484 | if ( line >= 0 ) |
1478 | 1485 | { |
1479 | 1486 | /* Fill column 0 with overscan color from m_reg[0x07] */ |
trunk/src/emu/video/315_5124.h
r22823 | r22824 | |
80 | 80 | DECLARE_READ8_MEMBER( register_read ); |
81 | 81 | DECLARE_WRITE8_MEMBER( register_write ); |
82 | 82 | DECLARE_READ8_MEMBER( vcount_read ); |
83 | | DECLARE_READ8_MEMBER( hcount_latch_read ); |
84 | | DECLARE_WRITE8_MEMBER( hcount_latch_write ); |
| 83 | DECLARE_READ8_MEMBER( hcount_read ); |
85 | 84 | |
| 85 | void hcount_latch() { hcount_latch_at_hpos( m_screen->hpos() ); }; |
| 86 | void hcount_latch_at_hpos( int hpos ); |
| 87 | |
86 | 88 | bitmap_rgb32 &get_bitmap() { return m_tmpbitmap; }; |
87 | 89 | bitmap_ind8 &get_y1_bitmap() { return m_y1_bitmap; }; |
88 | 90 | |
r22823 | r22824 | |
98 | 100 | virtual UINT16 get_name_table_address(); |
99 | 101 | void process_line_timer(); |
100 | 102 | void draw_scanline_mode4( int *line_buffer, int *priority_selected, int line ); |
101 | | void draw_sprites_mode4( int *line_buffer, int *priority_selected, int pixel_plot_y, int line ); |
102 | | void draw_sprites_tms9918_mode( int *line_buffer, int pixel_plot_y, int line ); |
| 103 | void draw_sprites_mode4( int *line_buffer, int *priority_selected, int line ); |
| 104 | void draw_sprites_tms9918_mode( int *line_buffer, int line ); |
103 | 105 | void draw_scanline_mode2( int *line_buffer, int line ); |
104 | 106 | void draw_scanline_mode0( int *line_buffer, int line ); |
105 | | void select_sprites( int pixel_plot_y, int line ); |
| 107 | void select_sprites( int line ); |
106 | 108 | void check_pending_flags( int hpos ); |
107 | 109 | |
108 | 110 | // device-level overrides |
trunk/src/mess/machine/sms.c
r22823 | r22824 | |
279 | 279 | } |
280 | 280 | } |
281 | 281 | |
282 | | /* FIXME: this function is a hack for Light Phaser emulation. Theoretically |
283 | | sms_vdp_hcount_latch() should be used instead, but it returns incorrect |
284 | | position for unknown reason (timing?) */ |
285 | | void sms_state::vdp_hcount_lphaser( int hpos ) |
286 | | { |
287 | | int hpos_tmp = hpos + m_lphaser_x_offs; |
288 | | UINT8 tmp = ((hpos_tmp - 46) >> 1) & 0xff; |
289 | 282 | |
290 | | //printf ("sms_vdp_hcount_lphaser: hpos %3d hpos_tmp %3d => hcount %2X\n", hpos, hpos_tmp, tmp); |
291 | | m_vdp->hcount_latch_write(*m_space, 0, tmp); |
292 | | } |
293 | | |
294 | | |
295 | 283 | /* |
296 | 284 | Light Phaser (light gun) emulation notes: |
297 | 285 | - The sensor is activated based on color brightness of some individual |
r22823 | r22824 | |
323 | 311 | int dx, dy; |
324 | 312 | int result = 0; |
325 | 313 | int pos_changed = 0; |
326 | | double dx_circ; |
| 314 | double dx_radius; |
327 | 315 | |
328 | 316 | while (1) |
329 | 317 | { |
| 318 | /* If beam's y isn't at a line where the aim area is, change it |
| 319 | the next line it enters that area. */ |
330 | 320 | dy = abs(beam_y - lgun_y); |
331 | | |
332 | 321 | if (dy > LGUN_RADIUS || beam_y < visarea.min_y || beam_y > visarea.max_y) |
333 | 322 | { |
334 | 323 | beam_y = lgun_y - LGUN_RADIUS; |
r22823 | r22824 | |
337 | 326 | dy = abs(beam_y - lgun_y); |
338 | 327 | pos_changed = 1; |
339 | 328 | } |
340 | | /* step 1: r^2 = dx^2 + dy^2 */ |
341 | | /* step 2: dx^2 = r^2 - dy^2 */ |
342 | | /* step 3: dx = sqrt(r^2 - dy^2) */ |
343 | | dx_circ = ceil((float) sqrt((float) (r_x_r - (dy * dy)))); |
344 | | dx = abs(beam_x - lgun_x); |
345 | 329 | |
346 | | if (dx > dx_circ || beam_x < visarea.min_x || beam_x > visarea.max_x) |
| 330 | /* Caculate distance in x of the radius, relative to beam's y distance. |
| 331 | First try some shortcuts. */ |
| 332 | switch (dy) |
| 333 | { |
| 334 | case LGUN_RADIUS: |
| 335 | dx_radius = 0; |
| 336 | break; |
| 337 | case 0: |
| 338 | dx_radius = LGUN_RADIUS; |
| 339 | break; |
| 340 | default: |
| 341 | /* step 1: r^2 = dx^2 + dy^2 */ |
| 342 | /* step 2: dx^2 = r^2 - dy^2 */ |
| 343 | /* step 3: dx = sqrt(r^2 - dy^2) */ |
| 344 | dx_radius = ceil((float) sqrt((float) (r_x_r - (dy * dy)))); |
| 345 | } |
| 346 | |
| 347 | /* If beam's x isn't in the circular aim area, change it |
| 348 | to the next point it enters that area. */ |
| 349 | dx = abs(beam_x - lgun_x); |
| 350 | if (dx > dx_radius || beam_x < visarea.min_x || beam_x > visarea.max_x) |
347 | 351 | { |
| 352 | /* If beam's x has passed the aim area, advance to |
| 353 | next line and recheck y/x coordinates. */ |
348 | 354 | if (beam_x > lgun_x) |
349 | 355 | { |
350 | 356 | beam_x = 0; |
351 | 357 | beam_y++; |
352 | 358 | continue; |
353 | 359 | } |
354 | | beam_x = lgun_x - dx_circ; |
| 360 | beam_x = lgun_x - dx_radius; |
355 | 361 | if (beam_x < visarea.min_x) |
356 | 362 | beam_x = visarea.min_x; |
357 | 363 | pos_changed = 1; |
r22823 | r22824 | |
389 | 395 | return result; |
390 | 396 | } |
391 | 397 | |
392 | | UINT8 sms_state::sms_vdp_hcount() |
393 | | { |
394 | | UINT64 cycles_per_line; |
395 | | attotime line_remaining_time; |
396 | | UINT64 line_remaining_cycles; |
397 | | UINT64 line_elapsed_cycles; |
398 | 398 | |
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; |
407 | | |
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; |
412 | | |
413 | | /* Alternative hcount equation, restricted to the SMS clock: |
414 | | "(590 - (line_remaining_cycles * 3)) / 4" |
415 | | Posted by Flubba on SMSPower forum. */ |
416 | | } |
417 | | |
418 | | |
419 | | void sms_state::sms_vdp_hcount_latch( address_space &space ) |
| 399 | void sms_state::lphaser_hcount_latch( int hpos ) |
420 | 400 | { |
421 | | UINT8 value = sms_vdp_hcount(); |
422 | | |
423 | | m_vdp->hcount_latch_write(space, 0, value); |
| 401 | /* A delay seems to occur when the Light Phaser latches the |
| 402 | VDP hcount, then an offset is added here to the hpos. */ |
| 403 | m_vdp->hcount_latch_at_hpos(hpos + m_lphaser_x_offs); |
424 | 404 | } |
425 | 405 | |
426 | 406 | |
427 | 407 | UINT16 sms_state::screen_hpos_nonscaled(int scaled_hpos) |
428 | 408 | { |
429 | 409 | const rectangle &visarea = m_main_scr->visible_area(); |
430 | | int offset_x = (scaled_hpos * visarea.width()) / 255; |
| 410 | int offset_x = (scaled_hpos * (visarea.max_x - visarea.min_x)) / 255; |
431 | 411 | return visarea.min_x + offset_x; |
432 | 412 | } |
433 | 413 | |
r22823 | r22824 | |
450 | 430 | if (m_lphaser_1_latch == 0) |
451 | 431 | { |
452 | 432 | m_lphaser_1_latch = 1; |
453 | | vdp_hcount_lphaser(x); |
| 433 | lphaser_hcount_latch(x); |
454 | 434 | } |
455 | 435 | } |
456 | 436 | } |
r22823 | r22824 | |
465 | 445 | if (m_lphaser_2_latch == 0) |
466 | 446 | { |
467 | 447 | m_lphaser_2_latch = 1; |
468 | | vdp_hcount_lphaser(x); |
| 448 | lphaser_hcount_latch(x); |
469 | 449 | } |
470 | 450 | } |
471 | 451 | } |
r22823 | r22824 | |
573 | 553 | |
574 | 554 | case 0x01: /* Light Phaser */ |
575 | 555 | data = (ioport("CTRLIPT")->read() & 0x01) << 4; |
576 | | if (!(data & 0x10)) |
577 | | { |
578 | | if (ioport("RFU")->read() & 0x01) |
579 | | data |= m_rapid_fire_state_1 & 0x10; |
580 | | } |
581 | | /* just consider the button (trigger) bit */ |
| 556 | /* Check Rapid Fire setting for Trigger */ |
| 557 | if (!(data & 0x10) && (ioport("RFU")->read() & 0x01)) |
| 558 | data |= m_rapid_fire_state_1 & 0x10; |
| 559 | |
| 560 | /* just consider the trigger (button) bit */ |
582 | 561 | data |= ~0x10; |
| 562 | |
583 | 563 | m_input_port0 = (m_input_port0 & 0xc0) | (data & 0x3f); |
584 | 564 | break; |
585 | 565 | |
r22823 | r22824 | |
635 | 615 | |
636 | 616 | case 0x10: /* Light Phaser */ |
637 | 617 | data = (ioport("CTRLIPT")->read() & 0x10) >> 2; |
638 | | if (!(data & 0x04)) |
639 | | { |
640 | | if (ioport("RFU")->read() & 0x04) |
641 | | data |= m_rapid_fire_state_2 & 0x04; |
642 | | } |
643 | | /* just consider the button (trigger) bit */ |
| 618 | /* Check Rapid Fire setting for Trigger */ |
| 619 | if (!(data & 0x04) && (ioport("RFU")->read() & 0x04)) |
| 620 | data |= m_rapid_fire_state_2 & 0x04; |
| 621 | |
| 622 | /* just consider the trigger (button) bit */ |
644 | 623 | data |= ~0x04; |
| 624 | |
645 | 625 | m_input_port1 = (m_input_port1 & 0xf0) | (data & 0x0f); |
646 | 626 | break; |
647 | 627 | |
r22823 | r22824 | |
708 | 688 | |
709 | 689 | WRITE8_MEMBER(sms_state::sms_io_control_w) |
710 | 690 | { |
711 | | bool hcount_latch = false; |
| 691 | bool latch_hcount = false; |
712 | 692 | |
713 | 693 | if (data & 0x08) |
714 | 694 | { |
715 | 695 | /* check if TH pin level is high (1) and was low last time */ |
716 | 696 | if (data & 0x80 && !(m_ctrl_reg & 0x80)) |
717 | 697 | { |
718 | | hcount_latch = true; |
| 698 | latch_hcount = true; |
719 | 699 | } |
720 | 700 | sms_input_write(space, 0, (data & 0x20) >> 5); |
721 | 701 | } |
r22823 | r22824 | |
724 | 704 | { |
725 | 705 | if (data & 0x20 && !(m_ctrl_reg & 0x20)) |
726 | 706 | { |
727 | | hcount_latch = true; |
| 707 | latch_hcount = true; |
728 | 708 | } |
729 | 709 | sms_input_write(space, 1, (data & 0x80) >> 7); |
730 | 710 | } |
731 | 711 | |
732 | | if (hcount_latch) |
| 712 | if (latch_hcount) |
733 | 713 | { |
734 | | sms_vdp_hcount_latch(space); |
| 714 | m_vdp->hcount_latch(); |
735 | 715 | } |
736 | 716 | |
737 | 717 | m_ctrl_reg = data; |
r22823 | r22824 | |
741 | 721 | READ8_MEMBER(sms_state::sms_count_r) |
742 | 722 | { |
743 | 723 | if (offset & 0x01) |
744 | | return m_vdp->hcount_latch_read(*m_space, offset); |
| 724 | return m_vdp->hcount_read(*m_space, offset); |
745 | 725 | else |
746 | 726 | return m_vdp->vcount_read(*m_space, offset); |
747 | 727 | } |
r22823 | r22824 | |
1531 | 1511 | if (!(m_bios_port & IO_CARTRIDGE) && m_cartridge[m_current_cartridge].size >= 0x8000) |
1532 | 1512 | { |
1533 | 1513 | if (!memcmp(&rom[0x7ff0], signatures[0], 16) || !memcmp(&rom[0x7ff0], signatures[1], 16)) |
1534 | | return 40; |
| 1514 | return 41; |
1535 | 1515 | |
1536 | 1516 | if (!memcmp(&rom[0x7ff0], signatures[2], 16)) |
1537 | | return 49; |
| 1517 | return 50; |
1538 | 1518 | |
1539 | 1519 | if (!memcmp(&rom[0x7ff0], signatures[3], 16)) |
1540 | | return 47; |
| 1520 | return 48; |
1541 | 1521 | |
1542 | 1522 | if (!memcmp(&rom[0x7ff0], signatures[4], 16)) |
1543 | | return 44; |
| 1523 | return 45; |
1544 | 1524 | |
1545 | 1525 | if (!memcmp(&rom[0x7ff0], signatures[5], 16)) |
1546 | | return 53; |
| 1526 | return 54; |
1547 | 1527 | |
1548 | 1528 | } |
1549 | | return 50; |
| 1529 | return 51; |
1550 | 1530 | } |
1551 | 1531 | |
1552 | 1532 | |
r22823 | r22824 | |
2260 | 2240 | |
2261 | 2241 | VIDEO_START_MEMBER(sms_state,gamegear) |
2262 | 2242 | { |
2263 | | screen_device *screen = machine().first_screen(); |
2264 | | |
2265 | | screen->register_screen_bitmap(m_prev_bitmap); |
| 2243 | m_main_scr->register_screen_bitmap(m_prev_bitmap); |
2266 | 2244 | save_item(NAME(m_prev_bitmap)); |
2267 | 2245 | } |
2268 | 2246 | |