src/mess/video/vdc.c
| r984 | r985 | |
| 49 | 49 | mame_bitmap *bmp; |
| 50 | 50 | }VCE; |
| 51 | 51 | |
| 52 | typedef struct { |
| 53 | UINT8 prio; |
| 54 | UINT8 vdc0_enabled; |
| 55 | UINT8 vdc1_enabled; |
| 56 | } VPC_PRIO; |
| 57 | |
| 58 | typedef struct { |
| 59 | VPC_PRIO vpc_prio[4]; |
| 60 | pair priority; /* Priority settings registers */ |
| 61 | pair window1; /* Window 1 setting */ |
| 62 | pair window2; /* Window 2 setting */ |
| 63 | UINT8 vdc_select; /* Which VDC do the ST0, ST1, and ST2 instructions write to */ |
| 64 | }VPC; |
| 65 | |
| 52 | 66 | static VDC vdc[2]; |
| 53 | 67 | static VCE vce; |
| 68 | static VPC vpc; |
| 54 | 69 | |
| 55 | 70 | /* Function prototypes */ |
| 56 | 71 | |
| 57 | 72 | static void vdc_advance_line(int which); |
| 58 | 73 | static void draw_black_line(int line); |
| 59 | 74 | static void draw_overscan_line(int line); |
| 60 | | static void pce_refresh_line(int which, int bitmap_line, int line, int external_input, UINT8 *drawn); |
| 61 | | static void pce_refresh_sprites(int which, int bitmap_line, int line, UINT8 *drawn); |
| 75 | static void draw_sgx_overscan_line(int line); |
| 76 | static void pce_refresh_line(int which, int line, int external_input, UINT8 *drawn, UINT16 *line_buffer); |
| 77 | static void pce_refresh_sprites(int which, int line, UINT8 *drawn, UINT16 *line_buffer); |
| 62 | 78 | static void vdc_do_dma(int which); |
| 79 | static void vpc_init( void ); |
| 63 | 80 | |
| 64 | 81 | INTERRUPT_GEN( pce_interrupt ) |
| 65 | 82 | { |
| r984 | r985 | |
| 75 | 92 | 1 - background pixel drawn |
| 76 | 93 | otherwise is 2 + sprite# */ |
| 77 | 94 | UINT8 drawn[VDC_WPF]; |
| 95 | /* our line buffer */ |
| 96 | UINT16 *line_buffer = BITMAP_ADDR16( vce.bmp, vce.current_bitmap_line, 86 ); |
| 78 | 97 | |
| 79 | 98 | /* clear our priority/sprite collision detection buffer. */ |
| 80 | 99 | memset(drawn, 0, VDC_WPF); |
| r984 | r985 | |
| 82 | 101 | vdc[0].y_scroll = ( vdc[0].current_segment_line == 0 ) ? vdc[0].vdc_data[BYR].w : ( vdc[0].y_scroll + 1 ); |
| 83 | 102 | |
| 84 | 103 | /* Draw VDC #0 background layer */ |
| 85 | | pce_refresh_line( 0, vce.current_bitmap_line, vdc[0].current_segment_line, 0, drawn ); |
| 104 | pce_refresh_line( 0, vdc[0].current_segment_line, 0, drawn, line_buffer ); |
| 86 | 105 | |
| 87 | 106 | /* Draw VDC #0 sprite layer */ |
| 88 | 107 | if(vdc[0].vdc_data[CR].w & CR_SB) { |
| 89 | | pce_refresh_sprites(0, vce.current_bitmap_line, vdc[0].current_segment_line, drawn); |
| 108 | pce_refresh_sprites(0, vdc[0].current_segment_line, drawn, line_buffer); |
| 90 | 109 | } |
| 91 | 110 | } |
| 92 | 111 | } else { |
| r984 | r985 | |
| 99 | 118 | vdc_advance_line( 0 ); |
| 100 | 119 | } |
| 101 | 120 | |
| 121 | INTERRUPT_GEN( sgx_interrupt ) |
| 122 | { |
| 123 | /* Draw the last scanline */ |
| 124 | if ( vce.current_bitmap_line >= 14 && vce.current_bitmap_line < 14 + 242 ) { |
| 125 | /* We are in the active display area */ |
| 126 | /* First fill the line with the overscan color */ |
| 127 | draw_sgx_overscan_line( vce.current_bitmap_line ); |
| 128 | |
| 129 | /* Check if we need to draw more just the overscan color */ |
| 130 | if ( vdc[0].current_segment == STATE_VDW ) { |
| 131 | /* 0 - no sprite and background pixels drawn |
| 132 | 1 - background pixel drawn |
| 133 | otherwise is 2 + sprite# */ |
| 134 | UINT8 drawn[2][VDC_WPF]; |
| 135 | UINT16 *line_buffer; |
| 136 | UINT16 temp_buffer[2][512]; |
| 137 | int i; |
| 138 | |
| 139 | /* clear our priority/sprite collision detection buffer. */ |
| 140 | memset(drawn, 0, sizeof(drawn)); |
| 141 | |
| 142 | vdc[0].y_scroll = ( vdc[0].current_segment_line == 0 ) ? vdc[0].vdc_data[BYR].w : ( vdc[0].y_scroll + 1 ); |
| 143 | vdc[1].y_scroll = ( vdc[1].current_segment_line == 0 ) ? vdc[1].vdc_data[BYR].w : ( vdc[1].y_scroll + 1 ); |
| 144 | |
| 145 | /* Draw VDC #0 background layer */ |
| 146 | pce_refresh_line( 0, vdc[0].current_segment_line, 0, drawn[0], temp_buffer[0] ); |
| 147 | |
| 148 | /* Draw VDC #0 sprite layer */ |
| 149 | if(vdc[0].vdc_data[CR].w & CR_SB) { |
| 150 | pce_refresh_sprites( 0, vdc[0].current_segment_line, drawn[0], temp_buffer[0] ); |
| 151 | } |
| 152 | |
| 153 | /* Draw VDC #1 background layer */ |
| 154 | pce_refresh_line( 1, vdc[1].current_segment_line, 1, drawn[1], temp_buffer[1] ); |
| 155 | |
| 156 | /* Draw VDC #1 sprite layer */ |
| 157 | if ( vdc[1].vdc_data[CR].w & CR_SB ) { |
| 158 | pce_refresh_sprites( 1, vdc[1].current_segment_line, drawn[1], temp_buffer[1] ); |
| 159 | } |
| 160 | |
| 161 | line_buffer = BITMAP_ADDR16( vce.bmp, vce.current_bitmap_line, 86 ); |
| 162 | /* Combine the output of both VDCs */ |
| 163 | for( i = 0; i < 512; i++ ) { |
| 164 | int cur_prio = 2; |
| 165 | |
| 166 | if ( vpc.vpc_prio[cur_prio].vdc0_enabled ) { |
| 167 | if ( vpc.vpc_prio[cur_prio].vdc1_enabled ) { |
| 168 | switch( vpc.vpc_prio[cur_prio].prio ) { |
| 169 | case 0: /* BG1 SP1 BG0 SP0 */ |
| 170 | if ( drawn[0][i] ) { |
| 171 | line_buffer[i] = temp_buffer[0][i]; |
| 172 | } else if ( drawn[1][i] ) { |
| 173 | line_buffer[i] = temp_buffer[1][i]; |
| 174 | } |
| 175 | break; |
| 176 | case 1: /* BG1 SP0 BG0 SP1 */ |
| 177 | // if ( drawn[0][i] ) { |
| 178 | // if ( drawn[1][i] > 1 ) { |
| 179 | // line_buffer[i] = temp_buffer[1][i]; |
| 180 | // } else { |
| 181 | // line_buffer[i] = temp_buffer[0][i]; |
| 182 | // } |
| 183 | // } else if ( drawn[1][i] ) { |
| 184 | // line_buffer[i] = temp_buffer[1][i]; |
| 185 | // } |
| 186 | // break; |
| 187 | case 2: /* BG1 BG0 SP1 SP0 */ |
| 188 | if ( drawn[0][i] ) { |
| 189 | if ( drawn[0][i] > 1 ) { |
| 190 | line_buffer[i] = temp_buffer[0][i]; |
| 191 | } else { |
| 192 | if ( drawn[1][i] > 1 ) { |
| 193 | line_buffer[i] = temp_buffer[1][i]; |
| 194 | } else { |
| 195 | line_buffer[i] = temp_buffer[0][i]; |
| 196 | } |
| 197 | } |
| 198 | } else if ( drawn[1][i] ) { |
| 199 | line_buffer[i] = temp_buffer[1][i]; |
| 200 | } |
| 201 | break; |
| 202 | } |
| 203 | } else { |
| 204 | if ( drawn[0][i] ) { |
| 205 | line_buffer[i] = temp_buffer[0][i]; |
| 206 | } |
| 207 | } |
| 208 | } else { |
| 209 | if ( vpc.vpc_prio[cur_prio].vdc1_enabled ) { |
| 210 | if ( drawn[1][i] ) { |
| 211 | line_buffer[i] = temp_buffer[1][i]; |
| 212 | } |
| 213 | } |
| 214 | } |
| 215 | } |
| 216 | } |
| 217 | } else { |
| 218 | /* We are in one of the blanking areas */ |
| 219 | draw_black_line( vce.current_bitmap_line ); |
| 220 | } |
| 221 | |
| 222 | /* bump current scanline */ |
| 223 | vce.current_bitmap_line = ( vce.current_bitmap_line + 1 ) % VDC_LPF; |
| 224 | vdc_advance_line( 0 ); |
| 225 | vdc_advance_line( 1 ); |
| 226 | } |
| 227 | |
| 102 | 228 | static void vdc_advance_line(int which) { |
| 103 | 229 | int ret = 0; |
| 104 | 230 | |
| r984 | r985 | |
| 215 | 341 | /* clear context */ |
| 216 | 342 | memset(&vdc, 0, sizeof(vdc)); |
| 217 | 343 | memset(&vce, 0, sizeof(vce)); |
| 344 | memset(&vpc, 0, sizeof(vpc)); |
| 218 | 345 | |
| 219 | 346 | /* allocate VRAM */ |
| 220 | 347 | vdc[0].vram = auto_malloc(0x10000); |
| r984 | r985 | |
| 227 | 354 | |
| 228 | 355 | vdc[0].inc = 1; |
| 229 | 356 | vdc[1].inc = 1; |
| 357 | |
| 358 | vpc_init(); |
| 230 | 359 | } |
| 231 | 360 | |
| 232 | 361 | |
| r984 | r985 | |
| 260 | 389 | |
| 261 | 390 | for ( i = 0; i < VDC_WPF; i++ ) |
| 262 | 391 | line_buffer[i] = Machine->pens[color_base + vce.vce_data[0x100].w]; |
| 392 | } |
| 263 | 393 | |
| 394 | static void draw_sgx_overscan_line(int line) { |
| 395 | int i; |
| 396 | |
| 397 | /* Are we in greyscale mode or in color mode? */ |
| 398 | int color_base = vce.vce_control & 0x80 ? 512 : 0; |
| 399 | |
| 400 | /* our line buffer */ |
| 401 | UINT16 *line_buffer = BITMAP_ADDR16( vce.bmp, line, 0 ); |
| 402 | |
| 403 | for ( i = 0; i < VDC_WPF; i++ ) |
| 404 | line_buffer[i] = Machine->pens[color_base + vce.vce_data[0].w]; |
| 264 | 405 | } |
| 265 | 406 | |
| 266 | 407 | static void vram_write(int which, offs_t offset, UINT8 data) |
| r984 | r985 | |
| 475 | 616 | } |
| 476 | 617 | |
| 477 | 618 | |
| 478 | | static void pce_refresh_line(int which, int bitmap_line, int line, int external_input, UINT8 *drawn) |
| 619 | static void pce_refresh_line(int which, int line, int external_input, UINT8 *drawn, UINT16 *line_buffer) |
| 479 | 620 | { |
| 480 | 621 | static int width_table[4] = {5, 6, 7, 7}; |
| 481 | 622 | |
| r984 | r985 | |
| 495 | 636 | /* virtual X size (# bits to shift) */ |
| 496 | 637 | int v_width = width_table[(vdc[which].vdc_data[MWR].w >> 4) & 3]; |
| 497 | 638 | |
| 498 | | /* our line buffer */ |
| 499 | | UINT16 *line_buffer = BITMAP_ADDR16( vce.bmp, bitmap_line, 86 ); |
| 500 | | |
| 501 | 639 | /* pointer to the name table (Background Attribute Table) in VRAM */ |
| 502 | 640 | UINT8 *bat = &(vdc[which].vram[nt_row << (v_width+1)]); |
| 503 | 641 | |
| r984 | r985 | |
| 513 | 651 | /* character blanking bit */ |
| 514 | 652 | if(!(vdc[which].vdc_data[CR].w & CR_BB)) |
| 515 | 653 | { |
| 516 | | draw_black_line(bitmap_line); |
| 654 | return; |
| 517 | 655 | } |
| 518 | 656 | else |
| 519 | 657 | { |
| r984 | r985 | |
| 554 | 692 | c &= 0x0F; |
| 555 | 693 | |
| 556 | 694 | if ( phys_x >= 0 && phys_x < vdc[which].physical_width ) { |
| 557 | | drawn[ phys_x ] = c ? 1 : 0; |
| 695 | drawn[ pixel ] = c ? 1 : 0; |
| 558 | 696 | if ( c || ! external_input ) |
| 559 | 697 | line_buffer[ pixel ] = Machine->pens[color_base + vce.vce_data[c].w]; |
| 560 | 698 | pixel++; |
| 561 | 699 | if ( vdc[which].physical_width != 512 ) { |
| 562 | 700 | if ( pixel < ( ( ( phys_x + 1 ) * 512 ) / vdc[which].physical_width ) ) { |
| 701 | drawn[ pixel ] = c ? 1 : 0; |
| 563 | 702 | if ( c || ! external_input ) |
| 564 | 703 | line_buffer[ pixel ] = Machine->pens[color_base + vce.vce_data[c].w]; |
| 565 | 704 | pixel++; |
| r984 | r985 | |
| 605 | 744 | } |
| 606 | 745 | } |
| 607 | 746 | |
| 608 | | static void pce_refresh_sprites(int which, int bitmap_line, int line, UINT8 *drawn) |
| 747 | static void pce_refresh_sprites(int which, int line, UINT8 *drawn, UINT16 *line_buffer) |
| 609 | 748 | { |
| 610 | 749 | int i; |
| 611 | 750 | UINT8 sprites_drawn=0; |
| 612 | | UINT16 *line_buffer= BITMAP_ADDR16( vce.bmp, bitmap_line, 86 ); |
| 613 | 751 | |
| 614 | 752 | /* Are we in greyscale mode or in color mode? */ |
| 615 | 753 | int color_base = vce.vce_control & 0x80 ? 512 : 0; |
| r984 | r985 | |
| 678 | 816 | if(((obj_x + x)<(vdc[which].physical_width))&&((obj_x + x)>=0)) |
| 679 | 817 | { |
| 680 | 818 | if ( buf[x] ) { |
| 681 | | if( drawn[obj_x+x] < 2 ) { |
| 682 | | if(priority || drawn[obj_x+x] == 0 ) { |
| 819 | if( drawn[pixel_x] < 2 ) { |
| 820 | drawn[pixel_x] = i + 2; |
| 821 | if(priority || drawn[pixel_x] == 0 ) { |
| 683 | 822 | line_buffer[pixel_x] = Machine->pens[color_base + vce.vce_data[0x100 + (palette << 4) + buf[x]].w]; |
| 684 | 823 | if ( vdc[which].physical_width != 512 ) { |
| 685 | 824 | if ( pixel_x + 1 < ( ( ( obj_x + x + 1 ) * 512 ) / vdc[which].physical_width ) ) { |
| 825 | drawn[pixel_x + 1] = i + 2; |
| 686 | 826 | line_buffer[pixel_x + 1] = Machine->pens[color_base + vce.vce_data[0x100 + (palette << 4) + buf[x]].w]; |
| 687 | 827 | } |
| 688 | 828 | } |
| 689 | 829 | } |
| 690 | | drawn[obj_x+x]=i+2; |
| 691 | 830 | } |
| 692 | 831 | /* Check for sprite #0 collision */ |
| 693 | | else if (drawn[obj_x+x]==2) |
| 832 | else if (drawn[pixel_x]==2) |
| 694 | 833 | { |
| 695 | 834 | if(vdc[which].vdc_data[CR].w&CR_CC) |
| 696 | 835 | cpunum_set_input_line(0, 0, ASSERT_LINE); |
| r984 | r985 | |
| 718 | 857 | if(((obj_x + x)<(vdc[which].physical_width))&&((obj_x + x)>=0)) |
| 719 | 858 | { |
| 720 | 859 | if ( buf[x] ) { |
| 721 | | if( drawn[obj_x+x] < 2 ) { |
| 722 | | if ( priority || drawn[obj_x+x] == 0 ) { |
| 860 | if( drawn[pixel_x] < 2 ) { |
| 861 | drawn[pixel_x] = i + 2; |
| 862 | if ( priority || drawn[pixel_x] == 0 ) { |
| 723 | 863 | line_buffer[pixel_x] = Machine->pens[color_base + vce.vce_data[0x100 + (palette << 4) + buf[x]].w]; |
| 724 | 864 | if ( vdc[which].physical_width != 512 ) { |
| 725 | 865 | if ( pixel_x + 1 < ( ( ( obj_x + x + 1 ) * 512 ) / vdc[which].physical_width ) ) { |
| 866 | drawn[pixel_x + 1] = i + 2; |
| 726 | 867 | line_buffer[pixel_x + 1] = Machine->pens[color_base + vce.vce_data[0x100 + (palette << 4) + buf[x]].w]; |
| 727 | 868 | } |
| 728 | 869 | } |
| 729 | 870 | } |
| 730 | | drawn[obj_x + x]=i+2; |
| 731 | 871 | } |
| 732 | 872 | /* Check for sprite #0 collision */ |
| 733 | | else if ( drawn[obj_x+x] == 2 ) { |
| 873 | else if ( drawn[pixel_x] == 2 ) { |
| 734 | 874 | if(vdc[which].vdc_data[CR].w&CR_CC) |
| 735 | 875 | cpunum_set_input_line(0, 0, ASSERT_LINE); |
| 736 | 876 | vdc[which].status|=VDC_CR; |
| r984 | r985 | |
| 760 | 900 | if(((obj_x + 0x10 + x)<(vdc[which].physical_width))&&((obj_x + 0x10 + x)>=0)) |
| 761 | 901 | { |
| 762 | 902 | if ( buf[x] ) { |
| 763 | | if( drawn[obj_x+0x10+x] < 2 ) { |
| 764 | | if( priority || drawn[obj_x+0x10+x] == 0 ) { |
| 903 | if( drawn[pixel_x] < 2 ) { |
| 904 | drawn[pixel_x] = i + 2; |
| 905 | if( priority || drawn[pixel_x] == 0 ) { |
| 765 | 906 | line_buffer[pixel_x] = Machine->pens[color_base + vce.vce_data[0x100 + (palette << 4) + buf[x]].w]; |
| 766 | 907 | if ( vdc[which].physical_width != 512 ) { |
| 767 | 908 | if ( pixel_x + 1 < ( ( ( obj_x + x + 17 ) * 512 ) / vdc[which].physical_width ) ) { |
| 909 | drawn[pixel_x + 1] = i + 2; |
| 768 | 910 | line_buffer[pixel_x + 1] = Machine->pens[color_base + vce.vce_data[0x100 + (palette << 4) + buf[x]].w]; |
| 769 | 911 | } |
| 770 | 912 | } |
| 771 | 913 | } |
| 772 | | drawn[obj_x + 0x10 + x]=i+2; |
| 773 | 914 | } |
| 774 | 915 | /* Check for sprite #0 collision */ |
| 775 | | else if ( drawn[obj_x+0x10+x]==2 ) { |
| 916 | else if ( drawn[pixel_x]==2 ) { |
| 776 | 917 | if(vdc[which].vdc_data[CR].w&CR_CC) |
| 777 | 918 | cpunum_set_input_line(0, 0, ASSERT_LINE); |
| 778 | 919 | vdc[which].status|=VDC_CR; |
| r984 | r985 | |
| 831 | 972 | } |
| 832 | 973 | |
| 833 | 974 | } |
| 975 | |
| 976 | WRITE8_HANDLER( vpc_w ) { |
| 977 | //printf("VPC write offset %02X, data %02X\n", offset, data ); |
| 978 | switch( offset & 0x07 ) { |
| 979 | case 0x00: /* Priority register #0 */ |
| 980 | vpc.priority.b.l = data; |
| 981 | vpc.vpc_prio[0].prio = ( data >> 2 ) & 3; |
| 982 | vpc.vpc_prio[0].vdc0_enabled = data & 1; |
| 983 | vpc.vpc_prio[0].vdc1_enabled = data & 2; |
| 984 | vpc.vpc_prio[1].prio = ( data >> 6 ) & 3; |
| 985 | vpc.vpc_prio[1].vdc0_enabled = data & 0x10; |
| 986 | vpc.vpc_prio[1].vdc1_enabled = data & 0x20; |
| 987 | break; |
| 988 | case 0x01: /* Priority register #1 */ |
| 989 | vpc.priority.b.h = data; |
| 990 | vpc.vpc_prio[2].prio = ( data >> 2 ) & 3; |
| 991 | vpc.vpc_prio[2].vdc0_enabled = data & 1; |
| 992 | vpc.vpc_prio[2].vdc1_enabled = data & 2; |
| 993 | vpc.vpc_prio[3].prio = ( data >> 6 ) & 3; |
| 994 | vpc.vpc_prio[3].vdc0_enabled = data & 0x10; |
| 995 | vpc.vpc_prio[3].vdc1_enabled = data & 0x20; |
| 996 | break; |
| 997 | case 0x02: /* Window 1 LSB */ |
| 998 | vpc.window1.b.l = data; |
| 999 | break; |
| 1000 | case 0x03: /* Window 1 MSB */ |
| 1001 | vpc.window1.b.h = data & 3; |
| 1002 | break; |
| 1003 | case 0x04: /* Window 2 LSB */ |
| 1004 | vpc.window2.b.l = data; |
| 1005 | break; |
| 1006 | case 0x05: /* Window 2 MSB */ |
| 1007 | vpc.window2.b.h = data & 3; |
| 1008 | break; |
| 1009 | case 0x06: /* VDC I/O select */ |
| 1010 | vpc.vdc_select = data & 1; |
| 1011 | break; |
| 1012 | } |
| 1013 | } |
| 1014 | |
| 1015 | READ8_HANDLER( vpc_r ) { |
| 1016 | UINT8 data = 0; |
| 1017 | switch( offset & 0x07 ) { |
| 1018 | case 0x00: /* Priority register #0 */ |
| 1019 | data = vpc.priority.b.l; |
| 1020 | break; |
| 1021 | case 0x01: /* Priority register #1 */ |
| 1022 | data = vpc.priority.b.h; |
| 1023 | break; |
| 1024 | case 0x02: /* Window 1 LSB */ |
| 1025 | data = vpc.window1.b.l; |
| 1026 | break; |
| 1027 | case 0x03: /* Window 1 MSB; high bits are 0 or 1? */ |
| 1028 | data = vpc.window1.b.h; |
| 1029 | break; |
| 1030 | case 0x04: /* Window 2 LSB */ |
| 1031 | data = vpc.window2.b.l; |
| 1032 | break; |
| 1033 | case 0x05: /* Window 2 MSB; high bits are 0 or 1? */ |
| 1034 | data = vpc.window2.b.h; |
| 1035 | break; |
| 1036 | } |
| 1037 | return data; |
| 1038 | } |
| 1039 | |
| 1040 | static void vpc_init( void ) { |
| 1041 | vpc_w( 0, 0x11 ); |
| 1042 | vpc_w( 1, 0x11 ); |
| 1043 | vpc.window1.w = 0; |
| 1044 | vpc.window2.w = 0; |
| 1045 | vpc.vdc_select = 0; |
| 1046 | } |
| 1047 | |
| 1048 | WRITE8_HANDLER( sgx_vdc_w ) { |
| 1049 | if ( vpc.vdc_select ) { |
| 1050 | vdc_1_w( offset, data ); |
| 1051 | } else { |
| 1052 | vdc_0_w( offset, data ); |
| 1053 | } |
| 1054 | } |
| 1055 | |
| 1056 | READ8_HANDLER( sgx_vdc_r ) { |
| 1057 | return ( vpc.vdc_select ) ? vdc_1_r( offset ) : vdc_0_r( offset ); |
| 1058 | } |
| 1059 | |