src/mess/machine/lynx.c
| r13635 | r13636 | |
| 79 | 79 | 0 0 0 0 0 0 0 1 exclusive-or the data |
| 80 | 80 | */ |
| 81 | 81 | |
| 82 | | INLINE void lynx_plot_pixel(lynx_state *state, const int mode, const int x, const int y, const int color) |
| 82 | INLINE void lynx_plot_pixel(lynx_state *state, const int mode, const INT16 x, const int y, const int color) |
| 83 | 83 | { |
| 84 | 84 | int back; |
| 85 | 85 | UINT8 *screen; |
| r13635 | r13636 | |
| 89 | 89 | screen = state->m_blitter.mem + state->m_blitter.screen + y * 80 + x / 2; |
| 90 | 90 | colbuf = state->m_blitter.mem + state->m_blitter.colbuf + y * 80 + x / 2; |
| 91 | 91 | |
| 92 | | switch (mode) |
| 92 | switch (mode&0x7) |
| 93 | 93 | { |
| 94 | 94 | case NORMAL_SPRITE: |
| 95 | 95 | /* A sprite may be set to 'normal'. This means that pen number '0' will be transparent and |
| r13635 | r13636 | |
| 297 | 297 | break; |
| 298 | 298 | if (!(x & 0x01)) /* Upper nibble */ |
| 299 | 299 | { |
| 300 | | *screen = (*screen & 0x0f)^(color<<4); |
| 301 | | |
| 300 | *screen = (*screen)^(color<<4); |
| 302 | 301 | if (color != 0x0e) |
| 303 | 302 | { |
| 304 | 303 | back = *colbuf; |
| r13635 | r13636 | |
| 310 | 309 | } |
| 311 | 310 | else /* Lower nibble */ |
| 312 | 311 | { |
| 313 | | *screen = (*screen & 0xf0)^color; |
| 314 | | |
| 312 | *screen = (*screen)^color; |
| 315 | 313 | if (color != 0x0e) |
| 316 | 314 | { |
| 317 | 315 | back = *colbuf; |
| r13635 | r13636 | |
| 326 | 324 | } |
| 327 | 325 | } |
| 328 | 326 | |
| 329 | | static void lynx_blit_do_work( lynx_state *state, const int y, const int xdir, const int bits, const int mask ) |
| 327 | static void lynx_blit_do_work( lynx_state *state, const int y, const int xdir, const int bits_per_pixel, const int mask ) |
| 330 | 328 | { |
| 331 | | int i,j; |
| 332 | | int xi, wi, b, p, color; |
| 329 | int next_line_addr,i,j; |
| 330 | int xi, bits, color; |
| 331 | UINT16 width_accum, buffer; |
| 333 | 332 | |
| 334 | | i = state->m_blitter.mem[state->m_blitter.bitmap]; // offset to second sprite line |
| 335 | | state->m_blitter.memory_accesses++; // ? |
| 336 | | for (xi = state->m_blitter.x, p = 0, b = 0, j = 1, wi = 0; j < i;) |
| 333 | next_line_addr = state->m_blitter.mem[state->m_blitter.bitmap]; // offset to second sprite line |
| 334 | width_accum = (xdir == 1) ? state->m_blitter.width_offset : 0; |
| 335 | state->m_blitter.memory_accesses++; |
| 336 | |
| 337 | for (xi = state->m_blitter.x_pos - state->m_blitter.xoff, bits = 0, buffer = 0, j = 1; j < next_line_addr;j++) |
| 337 | 338 | { |
| 338 | | if (p < bits) // less than one pixels worth of data left in buffer |
| 339 | buffer = (buffer << 8) | state->m_blitter.mem[state->m_blitter.bitmap + j]; |
| 340 | bits += 8; // current bits in buffer |
| 341 | state->m_blitter.memory_accesses++; |
| 342 | |
| 343 | for ( ; bits >= bits_per_pixel; bits -= bits_per_pixel) |
| 339 | 344 | { |
| 340 | | b = (b << 8) | state->m_blitter.mem[state->m_blitter.bitmap + j]; // shift next byte into buffer |
| 341 | | j++; // increment byte accumulator |
| 342 | | p += 8; // current bits in buffer |
| 343 | | state->m_blitter.memory_accesses++; |
| 344 | | } |
| 345 | | for ( ;(p >= bits); ) // as long as there is still one pixel of data remaining in buffer |
| 346 | | { |
| 347 | | color = state->m_blitter.color[(b >> (p - bits)) & mask]; |
| 348 | | p -= bits; |
| 349 | | for ( ; wi < state->m_blitter.width; wi += 0x100, xi += xdir) |
| 345 | color = state->m_blitter.color[(buffer >> (bits - bits_per_pixel)) & mask]; |
| 346 | //bits -= bits_per_pixel; |
| 347 | width_accum += state->m_blitter.width; |
| 348 | for (i = 0; i < (width_accum>>8); i++, xi += xdir) |
| 350 | 349 | { |
| 351 | 350 | if ((xi >= 0) && (xi < 160)) |
| 351 | { |
| 352 | 352 | lynx_plot_pixel(state, state->m_blitter.mode, xi, y, color); |
| 353 | } |
| 353 | 354 | } |
| 354 | | wi -= state->m_blitter.width; |
| 355 | width_accum &= 0xff; |
| 355 | 356 | } |
| 356 | 357 | } |
| 357 | 358 | } |
| r13635 | r13636 | |
| 410 | 411 | 1, 4 bit count of values-1, 4 bit color, .... |
| 411 | 412 | */ |
| 412 | 413 | |
| 413 | | static void lynx_blit_rle_do_work( lynx_state *state, const int y, const int xdir, const int bits, const int mask ) |
| 414 | static void lynx_blit_rle_do_work( lynx_state *state, const INT16 y, const int xdir, const int bits_per_pixel, const int mask ) |
| 414 | 415 | { |
| 415 | | int wi, xi; |
| 416 | | int b, p, j; |
| 417 | | int t, count, color; |
| 418 | | |
| 419 | | for( p = 0, j = 0, b = 0, xi = state->m_blitter.x, wi = 0; ; ) /* through the rle entries */ |
| 416 | int i; |
| 417 | int xi = state->m_blitter.x_pos - state->m_blitter.xoff; |
| 418 | int buffer, bits, j; |
| 419 | int literal_data, count, color; |
| 420 | UINT16 width_accum; |
| 421 | |
| 422 | width_accum = (xdir == 1) ? 0 : state->m_blitter.width_offset; |
| 423 | for( bits = 0, j = 0, buffer = 0, xi = state->m_blitter.x_pos - state->m_blitter.xoff; ; ) /* through the rle entries */ |
| 420 | 424 | { |
| 421 | | if (p < 5 + bits) /* under 7 bits no complete entry */ |
| 425 | if (bits < 5 + bits_per_pixel) /* under 7 bits no complete entry */ |
| 422 | 426 | { |
| 423 | 427 | j++; |
| 424 | 428 | if (j >= state->m_blitter.mem[state->m_blitter.bitmap]) |
| 425 | 429 | return; |
| 426 | 430 | |
| 427 | | p += 8; |
| 428 | | b = (b << 8) | state->m_blitter.mem[state->m_blitter.bitmap + j]; |
| 431 | bits += 8; |
| 432 | buffer = (buffer << 8) | state->m_blitter.mem[state->m_blitter.bitmap + j]; |
| 429 | 433 | state->m_blitter.memory_accesses++; |
| 430 | 434 | } |
| 431 | 435 | |
| 432 | | t = (b >> (p - 1)) & 0x01; |
| 433 | | p--; |
| 434 | | count = ((b >> (p - 4)) & 0x0f) + 1; // count value of zero means 1 pixel, thus the +1 |
| 435 | | p -= 4; |
| 436 | literal_data = (buffer >> (bits - 1)) & 0x01; |
| 437 | bits--; |
| 438 | count = (buffer >> (bits - 4)) & 0x0f; // repeat count (packed) or pixel count (literal) |
| 439 | bits -= 4; |
| 436 | 440 | |
| 437 | | if (t) /* count of different pixels */ |
| 438 | | { |
| 439 | | for ( ; count; count--) |
| 441 | if (literal_data) /* count of different pixels */ |
| 442 | { |
| 443 | for ( ; count >= 0; count--) |
| 440 | 444 | { |
| 441 | | if (p < bits) |
| 445 | if (bits < bits_per_pixel) |
| 442 | 446 | { |
| 443 | 447 | j++; |
| 444 | 448 | if (j >= state->m_blitter.mem[state->m_blitter.bitmap]) |
| 445 | 449 | return; |
| 446 | | p += 8; |
| 447 | | b = (b << 8) | state->m_blitter.mem[state->m_blitter.bitmap + j]; |
| 450 | bits += 8; |
| 451 | buffer = (buffer << 8) | state->m_blitter.mem[state->m_blitter.bitmap + j]; |
| 448 | 452 | state->m_blitter.memory_accesses++; |
| 449 | 453 | } |
| 450 | 454 | |
| 451 | | color = state->m_blitter.color[(b >> (p - bits)) & mask]; |
| 452 | | p -= bits; |
| 453 | | for ( ; wi < (state->m_blitter.width); wi += 0x100, xi += xdir) |
| 455 | color = state->m_blitter.color[(buffer >> (bits - bits_per_pixel)) & mask]; |
| 456 | bits -= bits_per_pixel; |
| 457 | width_accum += state->m_blitter.width; |
| 458 | for (i = 0; i < (width_accum>>8); i++, xi += xdir) |
| 454 | 459 | { |
| 455 | 460 | if ((xi >= 0) && (xi < 160)) |
| 456 | 461 | lynx_plot_pixel(state, state->m_blitter.mode, xi, y, color); |
| 457 | 462 | } |
| 458 | | wi -= state->m_blitter.width; |
| 463 | width_accum &= 0xff; |
| 459 | 464 | } |
| 460 | 465 | } |
| 461 | 466 | else /* count of same pixels */ |
| 462 | 467 | { |
| 463 | | if (count == 1) // 4 bit count value of zero indicates end-of-line in a packed sprite |
| 468 | if (count == 0) // 4 bit count value of zero indicates end-of-line in a packed sprite |
| 464 | 469 | return; |
| 465 | 470 | |
| 466 | | if (p < bits) |
| 471 | if (bits < bits_per_pixel) |
| 467 | 472 | { |
| 468 | 473 | j++; |
| 469 | 474 | if (j >= state->m_blitter.mem[state->m_blitter.bitmap]) |
| 470 | 475 | return; |
| 471 | | p += 8; |
| 472 | | b = (b << 8) | state->m_blitter.mem[state->m_blitter.bitmap + j]; |
| 476 | bits += 8; |
| 477 | buffer = (buffer << 8) | state->m_blitter.mem[state->m_blitter.bitmap + j]; |
| 473 | 478 | state->m_blitter.memory_accesses++; |
| 474 | 479 | } |
| 475 | 480 | |
| 476 | | color = state->m_blitter.color[(b >> (p - bits)) & mask]; |
| 477 | | p -= bits; |
| 481 | color = state->m_blitter.color[(buffer >> (bits - bits_per_pixel)) & mask]; |
| 482 | bits -= bits_per_pixel; |
| 478 | 483 | |
| 479 | | for ( ; count; count--) |
| 484 | for ( ; count>=0; count--) |
| 480 | 485 | { |
| 481 | | for ( ; (wi < state->m_blitter.width); wi += 0x100, xi += xdir) |
| 486 | width_accum += state->m_blitter.width; |
| 487 | for (i = 0; i < (width_accum>>8); i++, xi += xdir) |
| 482 | 488 | { |
| 483 | 489 | if ((xi >= 0) && (xi < 160)) |
| 484 | 490 | lynx_plot_pixel(state, state->m_blitter.mode, xi, y, color); |
| 485 | 491 | } |
| 486 | | wi -= state->m_blitter.width; |
| 492 | width_accum &= 0xff; |
| 487 | 493 | } |
| 488 | 494 | } |
| 489 | 495 | } |
| r13635 | r13636 | |
| 521 | 527 | |
| 522 | 528 | static void lynx_blit_lines(lynx_state *state) |
| 523 | 529 | { |
| 524 | | int i, hi, y; |
| 530 | int i; |
| 531 | INT16 y; |
| 525 | 532 | int ydir = 0, xdir = 0; |
| 526 | 533 | int flip = 0; |
| 527 | | int x_temp; |
| 528 | 534 | |
| 529 | 535 | state->m_blitter.everon = FALSE; |
| 530 | 536 | |
| 531 | | // flipping sprdemo3 |
| 532 | | // fat bobby 0x10 |
| 533 | | // mirror the sprite in gameplay? |
| 534 | | xdir = 1; |
| 535 | | |
| 536 | | if (state->m_blitter.spr_ctl0 & 0x20) /* Horizontal Flip */ |
| 537 | | { |
| 538 | | xdir = -1; |
| 539 | | //state->m_blitter.x--; // causes blank lines in todds adventures, klax, etc |
| 540 | | } |
| 541 | | |
| 542 | | ydir = 1; |
| 543 | | |
| 544 | | if (state->m_blitter.spr_ctl0 & 0x10) /* Vertical Flip */ |
| 545 | | { |
| 546 | | ydir = -1; |
| 547 | | //state->m_blitter.y--; // causes blank lines in todds adventures, klax, etc |
| 548 | | } |
| 549 | | |
| 550 | 537 | switch (state->m_blitter.spr_ctl1 & 0x03) /* Initial drawing direction */ |
| 551 | 538 | { |
| 552 | | case 0: // Down/Right |
| 539 | case 0: // Down/Right (quadrant 0) |
| 540 | xdir = 1; |
| 541 | ydir = 1; |
| 553 | 542 | flip = 0; |
| 554 | 543 | break; |
| 555 | | case 1: // Down/Left (blockout) |
| 556 | | xdir *= -1; |
| 544 | case 1: // Down/Left (blockout) (quadrant 3) |
| 545 | xdir = -1; |
| 546 | ydir = 1; |
| 557 | 547 | flip = 3; |
| 558 | 548 | break; |
| 559 | | case 2: // Up/Right (fat bobby) |
| 560 | | ydir *= -1; |
| 549 | case 2: // Up/Right (fat bobby) (quadrant 1) |
| 550 | xdir = 1; |
| 551 | ydir = -1; |
| 561 | 552 | flip = 1; |
| 562 | 553 | break; |
| 563 | | case 3: // Up/Left |
| 564 | | xdir *= -1; |
| 565 | | ydir *= -1; |
| 554 | case 3: // Up/Left (quadrant 2) |
| 555 | xdir = -1; |
| 556 | ydir = -1; |
| 566 | 557 | flip = 2; |
| 567 | 558 | break; |
| 568 | 559 | } |
| 569 | | |
| 570 | | x_temp = state->m_blitter.x; |
| 571 | | for (y = state->m_blitter.y, hi = 0; (i = state->m_blitter.mem[state->m_blitter.bitmap]); state->m_blitter.bitmap += i) |
| 560 | |
| 561 | if (state->m_blitter.spr_ctl0 & 0x20) /* Horizontal Flip */ |
| 572 | 562 | { |
| 563 | xdir *= -1; |
| 564 | //state->m_blitter.x_pos -= xdir; // causes blank lines in todds adventures, klax, etc |
| 565 | } |
| 566 | |
| 567 | if (state->m_blitter.spr_ctl0 & 0x10) /* Vertical Flip */ |
| 568 | { |
| 569 | ydir *= -1; |
| 570 | //state->m_blitter.y_pos -= ydir; // causes blank lines in todds adventures, klax, etc |
| 571 | } |
| 572 | |
| 573 | // Set height accumulator based on drawing direction |
| 574 | state->m_blitter.height_accumulator = (ydir == 1) ? state->m_blitter.height_offset : 0x00; |
| 575 | |
| 576 | for (y = state->m_blitter.y_pos - state->m_blitter.yoff; (i = state->m_blitter.mem[state->m_blitter.bitmap]); state->m_blitter.bitmap += i) |
| 577 | { |
| 573 | 578 | state->m_blitter.memory_accesses++; |
| 574 | | |
| 579 | |
| 575 | 580 | if (i == 1) // draw next quadrant |
| 576 | 581 | { |
| 577 | 582 | // centered sprites sprdemo3, fat bobby, blockout |
| 578 | | hi = 0; |
| 579 | 583 | switch (flip & 0x03) |
| 580 | 584 | { |
| 581 | 585 | case 0: |
| 582 | 586 | case 2: |
| 583 | 587 | ydir *= -1; |
| 584 | | state->m_blitter.y += ydir; |
| 588 | state->m_blitter.y_pos += ydir; |
| 585 | 589 | break; |
| 586 | | |
| 587 | 590 | case 1: |
| 588 | 591 | case 3: |
| 589 | 592 | xdir *= -1; |
| 590 | | state->m_blitter.x += xdir; |
| 591 | | x_temp += xdir; |
| 593 | state->m_blitter.x_pos += xdir; |
| 592 | 594 | break; |
| 593 | 595 | } |
| 594 | | |
| 595 | | y = state->m_blitter.y; |
| 596 | 596 | flip++; |
| 597 | y = state->m_blitter.y_pos - state->m_blitter.yoff; |
| 598 | state->m_blitter.height_accumulator = (ydir == 1) ? state->m_blitter.height_offset : 0x00; |
| 597 | 599 | continue; |
| 598 | 600 | } |
| 601 | |
| 602 | INT16 x = state->m_blitter.x_pos - state->m_blitter.xoff; |
| 603 | // superclipping |
| 604 | if (((x > 159) && (xdir == 1)) || ((x < 0) && (xdir == -1)) || ((y > 101) && (ydir == 1)) || ((y < 0) && (ydir == -1))) |
| 605 | continue; |
| 599 | 606 | |
| 600 | | for ( ; hi < (state->m_blitter.height); hi += 0x100, y += ydir) |
| 607 | state->m_blitter.height_accumulator += state->m_blitter.height; |
| 608 | for (int i=0; i < (state->m_blitter.height_accumulator>>8); i++, y += ydir) |
| 601 | 609 | { |
| 602 | 610 | if (y >= 0 && y < 102) |
| 603 | 611 | state->m_blitter.line_function(state, y, xdir); |
| r13635 | r13636 | |
| 608 | 616 | logerror("vertical stretch enabled"); |
| 609 | 617 | } |
| 610 | 618 | state->m_blitter.tilt_accumulator += state->m_blitter.tilt; |
| 611 | | state->m_blitter.x = x_temp + (INT8)((state->m_blitter.tilt_accumulator)>>8); |
| 619 | state->m_blitter.x_pos += (state->m_blitter.tilt_accumulator>>8); |
| 620 | state->m_blitter.tilt_accumulator &= 0xff; |
| 612 | 621 | } |
| 613 | | |
| 614 | | hi -= state->m_blitter.height; |
| 622 | state->m_blitter.height_accumulator &= 0xff; |
| 615 | 623 | } |
| 616 | 624 | |
| 617 | 625 | if (state->m_suzy.data[SPRGO] & 0x04) |
| r13635 | r13636 | |
| 726 | 734 | state->m_blitter.memory_accesses = 0; |
| 727 | 735 | state->m_blitter.mem = (UINT8*)machine.device("maincpu")->memory().space(AS_PROGRAM)->get_read_ptr(0x0000); |
| 728 | 736 | |
| 729 | | state->m_blitter.xoff = GET_WORD(state->m_suzy.data, HOFFL); |
| 730 | | state->m_blitter.yoff = GET_WORD(state->m_suzy.data, VOFFL); |
| 731 | | state->m_blitter.screen = GET_WORD(state->m_suzy.data, VIDBASL); |
| 732 | | state->m_blitter.colbuf = GET_WORD(state->m_suzy.data, COLLBASL); |
| 733 | | |
| 734 | 737 | // these might be never set by the state->m_blitter hardware |
| 735 | | //state->m_blitter.width = 0x100; |
| 736 | | //state->m_blitter.height = 0x100; |
| 737 | 738 | state->m_sprite_collide = 0; |
| 738 | 739 | |
| 739 | 740 | state->m_blitter.memory_accesses += 2; |
| r13635 | r13636 | |
| 753 | 754 | |
| 754 | 755 | state->m_blitter.spr_ctl0 = state->m_blitter.mem[state->m_blitter.scb + SCB_SPRCTL0]; |
| 755 | 756 | state->m_blitter.spr_ctl1 = state->m_blitter.mem[state->m_blitter.scb + SCB_SPRCTL1]; |
| 756 | | state->m_suzy.data[SPRCOLL] = state->m_blitter.mem[state->m_blitter.scb + SCB_SPRCOLL]; |
| 757 | state->m_blitter.spr_coll = state->m_blitter.mem[state->m_blitter.scb + SCB_SPRCOLL]; |
| 757 | 758 | |
| 758 | 759 | if(!(state->m_blitter.spr_ctl1 & 0x04)) // sprite will be processed (if sprite is skipped first 5 bytes are still copied to suzy) |
| 759 | 760 | { |
| 760 | 761 | state->m_blitter.bitmap = GET_WORD(state->m_blitter.mem, state->m_blitter.scb + SCB_SPRDLINE); |
| 761 | | state->m_suzy.data[HPOSSTRTL] = state->m_blitter.mem[state->m_blitter.scb + SCB_HPOSSTRT]; |
| 762 | | state->m_suzy.data[HPOSSTRTH] = state->m_blitter.mem[state->m_blitter.scb + SCB_HPOSSTRT+1]; |
| 763 | | state->m_suzy.data[VPOSSTRTL] = state->m_blitter.mem[state->m_blitter.scb + SCB_VPOSSTRT]; |
| 764 | | state->m_suzy.data[VPOSSTRTH] = state->m_blitter.mem[state->m_blitter.scb + SCB_VPOSSTRT+1]; |
| 762 | state->m_blitter.x_pos = GET_WORD(state->m_blitter.mem, state->m_blitter.scb + SCB_HPOSSTRT); |
| 763 | state->m_blitter.y_pos = GET_WORD(state->m_blitter.mem, state->m_blitter.scb + SCB_VPOSSTRT); |
| 765 | 764 | |
| 766 | 765 | switch(state->m_blitter.spr_ctl1 & 0x30) // reload sprite scaling |
| 767 | 766 | { |
| r13635 | r13636 | |
| 781 | 780 | else |
| 782 | 781 | palette_offset = 0x0b; |
| 783 | 782 | |
| 784 | | colors = lynx_colors[state->m_blitter.mem[state->m_blitter.scb] >> 6]; |
| 783 | colors = lynx_colors[state->m_blitter.spr_ctl0 >> 6]; |
| 785 | 784 | |
| 786 | 785 | for (i = 0; i < colors / 2; i++) |
| 787 | 786 | { |
| r13635 | r13636 | |
| 792 | 791 | } |
| 793 | 792 | } |
| 794 | 793 | |
| 795 | | |
| 796 | | |
| 797 | | |
| 798 | | |
| 794 | |
| 799 | 795 | if (!(state->m_blitter.spr_ctl1 & 0x04)) // if 0, we skip this sprite |
| 800 | 796 | { |
| 801 | 797 | state->m_blitter.colpos = GET_WORD(state->m_suzy.data, COLLOFFL) + state->m_blitter.scb; //???? |
| 802 | | state->m_blitter.x = (INT16)GET_WORD(state->m_suzy.data, HPOSSTRTL) - state->m_blitter.xoff; |
| 803 | | state->m_blitter.y = (INT16)GET_WORD(state->m_suzy.data, VPOSSTRTL) - state->m_blitter.yoff; |
| 804 | 798 | state->m_blitter.memory_accesses += 6; |
| 805 | 799 | |
| 806 | 800 | state->m_blitter.mode = state->m_blitter.spr_ctl0 & 0x07; |
| r13635 | r13636 | |
| 810 | 804 | else |
| 811 | 805 | state->m_blitter.line_function = blit_rle_line[state->m_blitter.spr_ctl0 >> 6]; |
| 812 | 806 | |
| 813 | | if (!(state->m_blitter.mem[state->m_blitter.scb + SCB_SPRCOLL] & 0x20) && !(state->m_suzy.data[SPRSYS] & 0x20)) |
| 807 | if (!(state->m_blitter.spr_coll & 0x20) && !(state->m_suzy.data[SPRSYS] & 0x20)) |
| 814 | 808 | { |
| 815 | 809 | switch (state->m_blitter.mode) |
| 816 | 810 | { |
| r13635 | r13636 | |
| 822 | 816 | case SHADOW: |
| 823 | 817 | state->m_sprite_collide = 1; |
| 824 | 818 | state->m_blitter.mem[state->m_blitter.colpos] = 0; |
| 825 | | state->m_blitter.spritenr = state->m_blitter.mem[state->m_blitter.scb + SCB_SPRCOLL] & 0x0f; |
| 819 | state->m_blitter.spritenr = state->m_blitter.spr_coll & 0x0f; |
| 826 | 820 | } |
| 827 | 821 | } |
| 828 | 822 | |
| r13635 | r13636 | |
| 971 | 965 | return state->m_blitter.scb_next & 0xff; |
| 972 | 966 | case SCBNEXTH: |
| 973 | 967 | return state->m_blitter.scb_next>>8; |
| 974 | | // case SPRDLINEL: |
| 975 | | // case HPOSSTRTL: |
| 976 | | // case VPOSSTRTL: |
| 968 | case SPRDLINEL: |
| 969 | return state->m_blitter.bitmap & 0xff; |
| 970 | case SPRDLINEH: |
| 971 | return state->m_blitter.bitmap>>8; |
| 972 | case HPOSSTRTL: |
| 973 | return state->m_blitter.x_pos & 0xff; |
| 974 | case HPOSSTRTH: |
| 975 | return state->m_blitter.x_pos>>8; |
| 976 | case VPOSSTRTL: |
| 977 | return state->m_blitter.y_pos & 0xff; |
| 978 | case VPOSSTRTH: |
| 979 | return state->m_blitter.y_pos>>8; |
| 977 | 980 | case SPRHSIZL: |
| 978 | 981 | return state->m_blitter.width & 0xff; |
| 979 | 982 | case SPRHSIZH: |
| r13635 | r13636 | |
| 993 | 996 | // case SPRDOFFL: |
| 994 | 997 | // case SPRVPOSL: |
| 995 | 998 | // case COLLOFFL: |
| 996 | | //case VSIZACUML: |
| 999 | case VSIZACUML: |
| 1000 | return state->m_blitter.height_accumulator & 0xff; |
| 1001 | case VSIZACUMH: |
| 1002 | return state->m_blitter.height_accumulator>>8; |
| 997 | 1003 | case HSIZOFFL: |
| 998 | 1004 | return state->m_blitter.width_offset & 0xff; |
| 999 | 1005 | case HSIZOFFH: |
| r13635 | r13636 | |
| 1007 | 1013 | case SCBADRH: |
| 1008 | 1014 | return state->m_blitter.scb>>8; |
| 1009 | 1015 | //case PROCADRL: |
| 1010 | | case SPRCTL0: |
| 1011 | | return state->m_blitter.spr_ctl0; |
| 1012 | | case SPRCTL1: |
| 1013 | | return state->m_blitter.spr_ctl1; |
| 1014 | 1016 | case SUZYHREV: |
| 1015 | 1017 | return 0x01; // must not be 0 for correct power up |
| 1016 | 1018 | case SPRSYS: /* Better check this with docs! */ |
| r13635 | r13636 | |
| 1067 | 1069 | value = *(space->machine().region("user1")->base() + (state->m_suzy.high * state->m_granularity) + state->m_suzy.low); |
| 1068 | 1070 | state->m_suzy.low = (state->m_suzy.low + 1) & (state->m_granularity - 1); |
| 1069 | 1071 | break; |
| 1070 | | case RCART_BANK1: /* we need bank 1 emulation!!! */ |
| 1072 | //case RCART_BANK1: /* we need bank 1 emulation!!! */ |
| 1073 | case SPRCTL0: |
| 1074 | case SPRCTL1: |
| 1075 | case SPRCOLL: |
| 1076 | case SPRINIT: |
| 1077 | //case SUZYBUSEN: |
| 1078 | case SPRGO: |
| 1079 | logerror("read from write only register %x\n", offset); |
| 1080 | value = 0; |
| 1081 | break; |
| 1071 | 1082 | default: |
| 1072 | 1083 | value = state->m_suzy.data[offset]; |
| 1073 | 1084 | } |
| 1074 | | // logerror("suzy read %.2x %.2x\n",offset,data); |
| 1085 | //logerror("suzy read %.2x %.2x\n",offset,value); |
| 1075 | 1086 | return value; |
| 1076 | 1087 | } |
| 1077 | 1088 | |
| r13635 | r13636 | |
| 1096 | 1107 | state->m_blitter.tilt_accumulator = data; // upper byte forced to zero see above. |
| 1097 | 1108 | break; |
| 1098 | 1109 | case TILTACUMH: |
| 1110 | state->m_blitter.tilt_accumulator &= 0xff; |
| 1099 | 1111 | state->m_blitter.tilt_accumulator |= data<<8; |
| 1100 | 1112 | break; |
| 1101 | 1113 | case HOFFL: |
| 1102 | 1114 | state->m_blitter.xoff = data; |
| 1103 | 1115 | break; |
| 1104 | 1116 | case HOFFH: |
| 1117 | state->m_blitter.xoff &= 0xff; |
| 1105 | 1118 | state->m_blitter.xoff |= data<<8; |
| 1106 | 1119 | break; |
| 1107 | 1120 | case VOFFL: |
| 1108 | 1121 | state->m_blitter.yoff = data; |
| 1109 | 1122 | break; |
| 1110 | 1123 | case VOFFH: |
| 1124 | state->m_blitter.yoff &= 0xff; |
| 1111 | 1125 | state->m_blitter.yoff |= data<<8; |
| 1112 | 1126 | break; |
| 1113 | 1127 | case VIDBASL: |
| 1114 | 1128 | state->m_blitter.screen = data; |
| 1115 | 1129 | break; |
| 1116 | 1130 | case VIDBASH: |
| 1131 | state->m_blitter.screen &= 0xff; |
| 1117 | 1132 | state->m_blitter.screen |= data<<8; |
| 1118 | 1133 | break; |
| 1119 | 1134 | case COLLBASL: |
| 1120 | 1135 | state->m_blitter.colbuf = data; |
| 1121 | 1136 | break; |
| 1122 | 1137 | case COLLBASH: |
| 1138 | state->m_blitter.colbuf &= 0xff; |
| 1123 | 1139 | state->m_blitter.colbuf |= data<<8; |
| 1124 | 1140 | break; |
| 1125 | 1141 | case SCBNEXTL: |
| 1126 | 1142 | state->m_blitter.scb_next = data; |
| 1127 | 1143 | break; |
| 1128 | 1144 | case SCBNEXTH: |
| 1145 | state->m_blitter.scb_next &= 0xff; |
| 1129 | 1146 | state->m_blitter.scb_next |= data<<8; |
| 1130 | 1147 | break; |
| 1131 | | // case SPRDLINEL: |
| 1132 | | // case HPOSSTRTL: |
| 1133 | | // case VPOSSTRTL: |
| 1148 | case SPRDLINEL: |
| 1149 | state->m_blitter.bitmap = data; |
| 1150 | break; |
| 1151 | case SPRDLINEH: |
| 1152 | state->m_blitter.bitmap &= 0xff; |
| 1153 | state->m_blitter.bitmap |= data<<8; |
| 1154 | break; |
| 1155 | case HPOSSTRTL: |
| 1156 | state->m_blitter.x_pos = data; |
| 1157 | case HPOSSTRTH: |
| 1158 | state->m_blitter.x_pos &= 0xff; |
| 1159 | state->m_blitter.x_pos |= data<<8; |
| 1160 | case VPOSSTRTL: |
| 1161 | state->m_blitter.y_pos = data; |
| 1162 | case VPOSSTRTH: |
| 1163 | state->m_blitter.y_pos &= 0xff; |
| 1164 | state->m_blitter.y_pos |= data<<8; |
| 1134 | 1165 | case SPRHSIZL: |
| 1135 | 1166 | state->m_blitter.width = data; |
| 1136 | 1167 | break; |
| 1137 | 1168 | case SPRHSIZH: |
| 1169 | state->m_blitter.width &= 0xff; |
| 1138 | 1170 | state->m_blitter.width |= data<<8; |
| 1139 | 1171 | break; |
| 1140 | 1172 | case SPRVSIZL: |
| 1141 | 1173 | state->m_blitter.height = data; |
| 1142 | 1174 | break; |
| 1143 | 1175 | case SPRVSIZH: |
| 1176 | state->m_blitter.height &= 0xff; |
| 1144 | 1177 | state->m_blitter.height |= data<<8; |
| 1145 | 1178 | break; |
| 1146 | 1179 | case STRETCHL: |
| 1147 | 1180 | state->m_blitter.stretch = data; |
| 1148 | 1181 | break; |
| 1149 | 1182 | case STRETCHH: |
| 1183 | state->m_blitter.stretch &= 0xff; |
| 1150 | 1184 | state->m_blitter.stretch |= data<<8; |
| 1151 | 1185 | break; |
| 1152 | 1186 | case TILTL: |
| 1153 | 1187 | state->m_blitter.stretch = data; |
| 1154 | 1188 | break; |
| 1155 | 1189 | case TILTH: |
| 1190 | state->m_blitter.stretch &= 0xff; |
| 1156 | 1191 | state->m_blitter.stretch |= data<<8; |
| 1157 | 1192 | break; |
| 1158 | 1193 | // case SPRDOFFL: |
| 1159 | 1194 | // case SPRVPOSL: |
| 1160 | 1195 | // case COLLOFFL: |
| 1161 | | //case VSIZACUML: |
| 1196 | case VSIZACUML: |
| 1197 | state->m_blitter.height_accumulator = data; |
| 1198 | break; |
| 1199 | case VSIZACUMH: |
| 1200 | state->m_blitter.height_accumulator &= 0xff; |
| 1201 | state->m_blitter.height_accumulator |= data<<8; |
| 1202 | break; |
| 1162 | 1203 | case HSIZOFFL: |
| 1163 | 1204 | state->m_blitter.width_offset = data; |
| 1164 | 1205 | break; |
| 1165 | 1206 | case HSIZOFFH: |
| 1207 | state->m_blitter.width_offset &= 0xff; |
| 1166 | 1208 | state->m_blitter.width_offset |= data<<8; |
| 1167 | 1209 | break; |
| 1168 | 1210 | case VSIZOFFL: |
| 1169 | 1211 | state->m_blitter.height_offset = data; |
| 1170 | 1212 | break; |
| 1171 | 1213 | case VSIZOFFH: |
| 1214 | state->m_blitter.height_offset &= 0xff; |
| 1172 | 1215 | state->m_blitter.height_offset |= data<<8; |
| 1173 | 1216 | break; |
| 1174 | 1217 | case SCBADRL: |
| 1175 | 1218 | state->m_blitter.scb = data; |
| 1176 | 1219 | break; |
| 1177 | 1220 | case SCBADRH: |
| 1221 | state->m_blitter.scb &= 0xff; |
| 1178 | 1222 | state->m_blitter.scb |= data<<8; |
| 1179 | 1223 | break; |
| 1180 | 1224 | //case PROCADRL: |
| r13635 | r13636 | |
| 1231 | 1275 | case SPRCTL1: |
| 1232 | 1276 | state->m_blitter.spr_ctl1 = data; |
| 1233 | 1277 | break; |
| 1278 | case SPRCOLL: |
| 1279 | state->m_blitter.spr_coll = data; |
| 1280 | break; |
| 1234 | 1281 | case SPRGO: |
| 1235 | 1282 | if (data & 0x01) |
| 1236 | 1283 | { |
| r13635 | r13636 | |
| 1238 | 1285 | lynx_blitter(space->machine()); |
| 1239 | 1286 | } |
| 1240 | 1287 | break; |
| 1288 | case JOYSTICK: |
| 1289 | case SWITCHES: |
| 1290 | logerror("warning: write to read-only button registers\n"); |
| 1291 | break; |
| 1241 | 1292 | } |
| 1242 | 1293 | } |
| 1243 | 1294 | |
| r13635 | r13636 | |
| 1311 | 1362 | return; |
| 1312 | 1363 | } |
| 1313 | 1364 | |
| 1314 | | // Documentation states lower two bits of buffer address are ignored (thus 0xfc mask) |
| 1315 | | j = ((state->m_mikey.data[0x94] & 0xfc) | (state->m_mikey.data[0x95]<<8)) + state->m_line_y * 160 / 2; |
| 1365 | // Documentation states lower two bits of buffer address are ignored (thus 0xfffc mask) |
| 1366 | j = (state->m_mikey.disp_addr & 0xfffc) + state->m_line_y * 160 / 2; |
| 1367 | |
| 1316 | 1368 | if (state->m_mikey.data[0x92] & 0x02) |
| 1369 | { |
| 1317 | 1370 | j -= 160 * 102 / 2 - 1; |
| 1318 | | |
| 1319 | | if (state->m_mikey.data[0x92] & 0x02) |
| 1320 | | { |
| 1321 | 1371 | for ( ; state->m_line_y < yend; state->m_line_y++) |
| 1322 | 1372 | { |
| 1323 | 1373 | line = BITMAP_ADDR16(machine.generic.tmpbitmap, 102 - 1 - state->m_line_y, 0); |
| r13635 | r13636 | |
| 1408 | 1458 | switch ( which ) // count down linked timers |
| 1409 | 1459 | { |
| 1410 | 1460 | case 0: |
| 1461 | if ((state->m_line == 2) || (state->m_line == 3) || (state->m_line == 4)) |
| 1462 | { |
| 1463 | //state->m_mikey.vb_rest = 1; |
| 1464 | } |
| 1465 | else |
| 1466 | state->m_mikey.vb_rest = 0; |
| 1467 | if (state->m_line == 3) |
| 1468 | { |
| 1469 | state->m_mikey.disp_addr = state->m_mikey.data[0x94] | (state->m_mikey.data[0x95] << 8); |
| 1470 | lynx_draw_lines( machine, -1 ); |
| 1471 | } |
| 1411 | 1472 | lynx_timer_count_down( machine, 2 ); |
| 1412 | 1473 | state->m_line++; |
| 1413 | 1474 | break; |
| r13635 | r13636 | |
| 1444 | 1505 | if ( state->m_timer[which].counter == 0 ) |
| 1445 | 1506 | { |
| 1446 | 1507 | state->m_timer[which].cntrl2 |= 8; // set timer done |
| 1447 | | lynx_timer_signal_irq(machine, which); |
| 1448 | | if ( state->m_timer[which].cntrl1 & 0x10 ) // if reload enabled |
| 1449 | | { |
| 1450 | | state->m_timer[which].counter = state->m_timer[which].bakup; |
| 1508 | lynx_timer_signal_irq(machine, which); |
| 1509 | if ( state->m_timer[which].cntrl1 & 0x10 ) // if reload enabled |
| 1510 | { |
| 1511 | state->m_timer[which].counter = state->m_timer[which].bakup; |
| 1451 | 1512 | // should we unset timer done? |
| 1452 | | } |
| 1453 | | else |
| 1454 | | { |
| 1513 | } |
| 1514 | else |
| 1515 | { |
| 1455 | 1516 | state->m_timer[which].counter--; // Is this correct or should it stop at zero? |
| 1456 | | } |
| 1517 | } |
| 1457 | 1518 | return; |
| 1458 | 1519 | } |
| 1459 | 1520 | } |
| r13635 | r13636 | |
| 1539 | 1600 | state->m_timer[which].counter = data; |
| 1540 | 1601 | break; |
| 1541 | 1602 | case 3: |
| 1542 | | // Should we be ignoring writes to the timer done bit? |
| 1543 | | state->m_timer[which].cntrl2 = (state->m_timer[which].cntrl2 & 0x08) | (data & ~0x08); |
| 1603 | state->m_timer[which].cntrl2 = (state->m_timer[which].cntrl2 & ~0x08) | (data & 0x08); |
| 1544 | 1604 | break; |
| 1545 | 1605 | } |
| 1546 | 1606 | |
| r13635 | r13636 | |
| 1704 | 1764 | value |= (direction & 0x01) ? (state->m_mikey.data[offset] & 0x01) : 0x01; // External Power input |
| 1705 | 1765 | value |= (direction & 0x02) ? (state->m_mikey.data[offset] & 0x02) : 0x00; // Cart Address Data output (0 turns cart power on) |
| 1706 | 1766 | value |= (direction & 0x04) ? (state->m_mikey.data[offset] & 0x04) : 0x04; // noexp input |
| 1707 | | // REST read returns actual rest state anded with rest output bit (to be implemented) |
| 1708 | | value |= (direction & 0x08) ? (state->m_mikey.data[offset] & 0x08) : 0x00; // rest output |
| 1767 | // REST read returns actual rest state anded with rest output bit |
| 1768 | value |= (direction & 0x08) ? (state->m_mikey.data[offset] & 0x08) & (state->m_mikey.vb_rest<<3) : 0x00; // rest output |
| 1709 | 1769 | value |= (direction & 0x10) ? (state->m_mikey.data[offset] & 0x10) : 0x10; // audin input |
| 1710 | 1770 | /* Hack: we disable COMLynx */ |
| 1711 | 1771 | value |= 0x04; |
| r13635 | r13636 | |
| 1721 | 1781 | value = state->m_mikey.data[offset]; |
| 1722 | 1782 | //logerror( "mikey read %.2x %.2x\n", offset, value ); |
| 1723 | 1783 | } |
| 1724 | | |
| 1725 | 1784 | return value; |
| 1726 | 1785 | } |
| 1727 | 1786 | |
| r13635 | r13636 | |
| 1817 | 1876 | //logerror("CPUSLEEP request \n"); |
| 1818 | 1877 | } |
| 1819 | 1878 | break; |
| 1879 | case 0x94: case 0x95: |
| 1880 | state->m_mikey.data[offset]=data; |
| 1881 | break; |
| 1882 | case 0x9c: case 0x9d: case 0x9e: |
| 1883 | state->m_mikey.data[offset]=data; |
| 1884 | logerror("Mtest%d write: %x\n", offset&0x3, data); |
| 1885 | break; |
| 1820 | 1886 | |
| 1821 | 1887 | default: |
| 1822 | 1888 | state->m_mikey.data[offset]=data; |
| r13635 | r13636 | |
| 1884 | 1950 | state->m_mikey.data[0x90] = 0x00; |
| 1885 | 1951 | state->m_mikey.data[0x92] = 0x00; |
| 1886 | 1952 | |
| 1953 | /* |
| 1954 | state->m_suzy.data[MATH_A] = 0xff; |
| 1955 | state->m_suzy.data[MATH_B] = 0xff; |
| 1956 | state->m_suzy.data[MATH_C] = 0xff; |
| 1957 | state->m_suzy.data[MATH_D] = 0xff; |
| 1958 | |
| 1959 | state->m_suzy.data[MATH_E] = 0xff; |
| 1960 | state->m_suzy.data[MATH_F] = 0xff; |
| 1961 | state->m_suzy.data[MATH_G] = 0xff; |
| 1962 | state->m_suzy.data[MATH_H] = 0xff; |
| 1963 | |
| 1964 | state->m_suzy.data[MATH_J] = 0xff; |
| 1965 | state->m_suzy.data[MATH_K] = 0xff; |
| 1966 | state->m_suzy.data[MATH_L] = 0xff; |
| 1967 | state->m_suzy.data[MATH_M] = 0xff; |
| 1968 | state->m_suzy.data[MATH_P] = 0xff; |
| 1969 | */ |
| 1970 | |
| 1887 | 1971 | lynx_uart_reset(state); |
| 1888 | 1972 | |
| 1889 | 1973 | // hack to allow current object loading to work |