src/mame/machine/snes.c
| r7539 | r7540 | |
| 777 | 777 | snes_ppu.screen_brightness = (data & 0x0f) + 1; |
| 778 | 778 | break; |
| 779 | 779 | case OBSEL: /* Object size and data area designation */ |
| 780 | | snes_ppu.layer[SNES_OAM].charmap = (data & 0x03) << 1; |
| 781 | | snes_ppu.oam.name_select = (((data & 0x18) >> 3) * 0x1000) << 1; |
| 782 | | /* Determine object size */ |
| 783 | | switch ((data & 0xe0) >> 5) |
| 784 | | { |
| 785 | | case 0: /* 8 & 16 */ |
| 786 | | snes_ppu.oam.size[0] = 1; |
| 787 | | snes_ppu.oam.size[1] = 2; |
| 788 | | break; |
| 789 | | case 1: /* 8 & 32 */ |
| 790 | | snes_ppu.oam.size[0] = 1; |
| 791 | | snes_ppu.oam.size[1] = 4; |
| 792 | | break; |
| 793 | | case 2: /* 8 & 64 */ |
| 794 | | snes_ppu.oam.size[0] = 1; |
| 795 | | snes_ppu.oam.size[1] = 8; |
| 796 | | break; |
| 797 | | case 3: /* 16 & 32 */ |
| 798 | | snes_ppu.oam.size[0] = 2; |
| 799 | | snes_ppu.oam.size[1] = 4; |
| 800 | | break; |
| 801 | | case 4: /* 16 & 64 */ |
| 802 | | snes_ppu.oam.size[0] = 2; |
| 803 | | snes_ppu.oam.size[1] = 8; |
| 804 | | break; |
| 805 | | case 5: /* 32 & 64 */ |
| 806 | | snes_ppu.oam.size[0] = 4; |
| 807 | | snes_ppu.oam.size[1] = 8; |
| 808 | | break; |
| 809 | | default: |
| 810 | | /* Unknown size so default to 8 & 16 */ |
| 811 | | logerror("Object size unsupported: %d\n", (data & 0xe0) >> 5); |
| 812 | | |
| 813 | | snes_ppu.oam.size[0] = 1; |
| 814 | | snes_ppu.oam.size[1] = 2; |
| 815 | | #ifdef SNES_DBG_REG_W |
| 816 | | mame_printf_debug("Object size unsupported: %d\n", (data & 0xe0) >> 5); |
| 817 | | #endif |
| 818 | | } |
| 780 | snes_ppu.oam.next_charmap = (data & 0x03) << 1; |
| 781 | snes_ppu.oam.next_name_select = (((data & 0x18) >> 3) * 0x1000) << 1; |
| 782 | snes_ppu.oam.next_size = (data & 0xe0) >> 5; |
| 819 | 783 | break; |
| 820 | 784 | case OAMADDL: /* Address for accessing OAM (low) */ |
| 821 | 785 | snes_ppu.oam.address_low = data; |
| r7539 | r7540 | |
| 827 | 791 | snes_ppu.oam.address_high = data & 0x1; |
| 828 | 792 | snes_ppu.oam.saved_address_high = data; |
| 829 | 793 | snes_ppu.oam.address = ((data & 0x1) << 8) + snes_ppu.oam.address_low; |
| 830 | | snes_ppu.oam.priority_rotation = (data & 0x80) ? 1 : 0; |
| 794 | snes_ppu.oam.priority_rotation = BIT(data, 7); |
| 831 | 795 | snes_ram[OAMDATA] = 0; |
| 832 | 796 | break; |
| 833 | 797 | case OAMDATA: /* Data for OAM write (DW) */ |
src/mame/video/snes.c
| r7539 | r7540 | |
| 989 | 989 | * FIXME: We need to support high priority bit |
| 990 | 990 | *********************************************/ |
| 991 | 991 | |
| 992 | struct OAM |
| 993 | { |
| 994 | UINT16 tile; |
| 995 | INT16 x, y; |
| 996 | UINT8 size, vflip, hflip, priority_bits, pal; |
| 997 | int height, width; |
| 998 | }; |
| 999 | |
| 1000 | static struct OAM oam_list[SNES_SCR_WIDTH / 2]; |
| 1001 | |
| 1002 | static void snes_update_obsel( void ) |
| 1003 | { |
| 1004 | snes_ppu.layer[SNES_OAM].charmap = snes_ppu.oam.next_charmap; |
| 1005 | snes_ppu.oam.name_select = snes_ppu.oam.next_name_select; |
| 1006 | |
| 1007 | if (snes_ppu.oam.size != snes_ppu.oam.next_size) |
| 1008 | { |
| 1009 | snes_ppu.oam.size = snes_ppu.oam.next_size; |
| 1010 | snes_ppu.update_oam_list = 1; |
| 1011 | } |
| 1012 | } |
| 1013 | |
| 1014 | static void snes_oam_list_build( void ) |
| 1015 | { |
| 1016 | UINT8 *oamram = (UINT8 *)snes_oam; |
| 1017 | INT16 oam = 0x1ff; |
| 1018 | UINT16 oam_extra = oam + 0x20; |
| 1019 | UINT16 extra = 0; |
| 1020 | int i; |
| 1021 | |
| 1022 | snes_ppu.update_oam_list = 0; // eventually, we can optimize the code by only calling this function when there is a change in size |
| 1023 | |
| 1024 | for (i = 128; i > 0; i--) |
| 1025 | { |
| 1026 | if ((i % 4) == 0) |
| 1027 | extra = oamram[oam_extra--]; |
| 1028 | |
| 1029 | oam_list[i].vflip = (oamram[oam] & 0x80) >> 7; |
| 1030 | oam_list[i].hflip = (oamram[oam] & 0x40) >> 6; |
| 1031 | oam_list[i].priority_bits = (oamram[oam] & 0x30) >> 4; |
| 1032 | oam_list[i].pal = 128 + ((oamram[oam] & 0x0e) << 3); |
| 1033 | oam_list[i].tile = (oamram[oam--] & 0x1) << 8; |
| 1034 | oam_list[i].tile |= oamram[oam--]; |
| 1035 | oam_list[i].y = oamram[oam--] + 1; /* We seem to need to add one here.... */ |
| 1036 | oam_list[i].x = oamram[oam--]; |
| 1037 | oam_list[i].size = (extra & 0x80) >> 7; |
| 1038 | extra <<= 1; |
| 1039 | oam_list[i].x |= ((extra & 0x80) << 1); |
| 1040 | extra <<= 1; |
| 1041 | oam_list[i].y *= snes_ppu.obj_interlace; |
| 1042 | |
| 1043 | /* Adjust if past maximum position */ |
| 1044 | if (oam_list[i].y >= snes_ppu.beam.last_visible_line * snes_ppu.interlace) |
| 1045 | oam_list[i].y -= 256 * snes_ppu.interlace; |
| 1046 | if (oam_list[i].x > 255) |
| 1047 | oam_list[i].x -= 512; |
| 1048 | |
| 1049 | /* Determine object size */ |
| 1050 | switch (snes_ppu.oam.size) |
| 1051 | { |
| 1052 | case 0: /* 8x8 or 16x16 */ |
| 1053 | oam_list[i].width = oam_list[i].size ? 2 : 1; |
| 1054 | oam_list[i].height = oam_list[i].size ? 2 : 1; |
| 1055 | break; |
| 1056 | case 1: /* 8x8 or 32x32 */ |
| 1057 | oam_list[i].width = oam_list[i].size ? 4 : 1; |
| 1058 | oam_list[i].height = oam_list[i].size ? 4 : 1; |
| 1059 | break; |
| 1060 | case 2: /* 8x8 or 64x64 */ |
| 1061 | oam_list[i].width = oam_list[i].size ? 8 : 1; |
| 1062 | oam_list[i].height = oam_list[i].size ? 8 : 1; |
| 1063 | break; |
| 1064 | case 3: /* 16x16 or 32x32 */ |
| 1065 | oam_list[i].width = oam_list[i].size ? 4 : 2; |
| 1066 | oam_list[i].height = oam_list[i].size ? 4 : 2; |
| 1067 | break; |
| 1068 | case 4: /* 16x16 or 64x64 */ |
| 1069 | oam_list[i].width = oam_list[i].size ? 8 : 2; |
| 1070 | oam_list[i].height = oam_list[i].size ? 8 : 2; |
| 1071 | break; |
| 1072 | case 5: /* 32x32 or 64x64 */ |
| 1073 | oam_list[i].width = oam_list[i].size ? 8 : 4; |
| 1074 | oam_list[i].height = oam_list[i].size ? 8 : 4; |
| 1075 | break; |
| 1076 | case 6: /* undocumented: 16x32 or 32x64 */ |
| 1077 | oam_list[i].width = oam_list[i].size ? 4 : 2; |
| 1078 | oam_list[i].height = oam_list[i].size ? 8 : 4; |
| 1079 | if (snes_ppu.obj_interlace && !oam_list[i].size) |
| 1080 | oam_list[i].height = 2; |
| 1081 | break; |
| 1082 | case 7: /* undocumented: 16x32 or 32x32 */ |
| 1083 | oam_list[i].width = oam_list[i].size ? 4 : 2; |
| 1084 | oam_list[i].height = oam_list[i].size ? 4 : 4; |
| 1085 | if (snes_ppu.obj_interlace && !oam_list[i].size) |
| 1086 | oam_list[i].height = 2; |
| 1087 | break; |
| 1088 | default: |
| 1089 | /* we should never enter here... */ |
| 1090 | logerror("Object size unsupported: %d\n", snes_ppu.oam.size); |
| 1091 | break; |
| 1092 | } |
| 1093 | } |
| 1094 | } |
| 1095 | |
| 992 | 1096 | static void snes_update_objects( UINT8 priority_tbl, UINT16 curline ) |
| 993 | 1097 | { |
| 994 | 1098 | INT8 xs, ys; |
| 995 | 1099 | UINT8 line; |
| 996 | | UINT16 oam_extra, extra; |
| 997 | | INT16 oam; |
| 998 | 1100 | UINT8 range_over = 0, time_over = 0; |
| 999 | | UINT8 size, vflip, hflip, priority, pal, blend; |
| 1101 | UINT8 height, width, vflip, hflip, priority, pal, blend; |
| 1000 | 1102 | UINT16 tile; |
| 1001 | 1103 | INT16 i, x, y; |
| 1002 | | UINT8 *oamram = (UINT8 *)snes_oam; |
| 1003 | 1104 | UINT32 name_sel = 0, charaddr; |
| 1004 | 1105 | static const UINT8 table_obj_priority[10][4] = { |
| 1005 | 1106 | {2, 5, 8, 11}, // mode 0 |
| r7539 | r7540 | |
| 1032 | 1133 | |
| 1033 | 1134 | charaddr = snes_ppu.layer[SNES_OAM].charmap << 13; |
| 1034 | 1135 | |
| 1035 | | oam = 0x1ff; |
| 1036 | | oam_extra = oam + 0x20; |
| 1037 | | extra = 0; |
| 1038 | 1136 | for (i = 128; i > 0; i--) |
| 1039 | 1137 | { |
| 1040 | | if ((i % 4) == 0) |
| 1041 | | extra = oamram[oam_extra--]; |
| 1138 | tile = oam_list[i].tile; |
| 1139 | x = oam_list[i].x; |
| 1140 | y = oam_list[i].y; |
| 1141 | height = oam_list[i].height; |
| 1142 | width = oam_list[i].width; |
| 1143 | vflip = oam_list[i].vflip; |
| 1144 | hflip = oam_list[i].hflip; |
| 1145 | priority = table_obj_priority[priority_tbl][oam_list[i].priority_bits]; |
| 1146 | pal = oam_list[i].pal; |
| 1042 | 1147 | |
| 1043 | | vflip = (oamram[oam] & 0x80) >> 7; |
| 1044 | | hflip = (oamram[oam] & 0x40) >> 6; |
| 1045 | | priority = table_obj_priority[priority_tbl][(oamram[oam] & 0x30) >> 4]; |
| 1046 | | pal = 128 + ((oamram[oam] & 0x0e) << 3); |
| 1047 | | tile = (oamram[oam--] & 0x1) << 8; |
| 1048 | | tile |= oamram[oam--]; |
| 1049 | | y = oamram[oam--] + 1; /* We seem to need to add one here.... */ |
| 1050 | | x = oamram[oam--]; |
| 1051 | | size = (extra & 0x80) >> 7; |
| 1052 | | extra <<= 1; |
| 1053 | | x |= ((extra & 0x80) << 1); |
| 1054 | | extra <<= 1; |
| 1055 | | y *= snes_ppu.obj_interlace; |
| 1056 | | |
| 1057 | | /* Adjust if past maximum position */ |
| 1058 | | if (y >= snes_ppu.beam.last_visible_line*snes_ppu.interlace) |
| 1059 | | y -= 256*snes_ppu.interlace; |
| 1060 | | if (x > 255) |
| 1061 | | x -= 512; |
| 1062 | | |
| 1063 | 1148 | /* Draw sprite if it intersects the current line */ |
| 1064 | | if (curline >= y && curline < (y + (snes_ppu.oam.size[size] << 3))) |
| 1149 | if (curline >= y && curline < (y + (height << 3))) |
| 1065 | 1150 | { |
| 1066 | 1151 | /* Only objects using palettes 4-7 can be transparent */ |
| 1067 | 1152 | blend = (pal < 192) ? 1 : 0; |
| r7539 | r7540 | |
| 1073 | 1158 | line = (curline - y) % 8; |
| 1074 | 1159 | if (vflip) |
| 1075 | 1160 | { |
| 1076 | | ys = snes_ppu.oam.size[size] - ys - 1; |
| 1161 | ys = height - ys - 1; |
| 1077 | 1162 | line = (-1 * line) + 7; |
| 1078 | 1163 | } |
| 1079 | 1164 | line <<= 1; |
| r7539 | r7540 | |
| 1081 | 1166 | if (hflip) |
| 1082 | 1167 | { |
| 1083 | 1168 | UINT8 count = 0; |
| 1084 | | for (xs = (snes_ppu.oam.size[size] - 1); xs >= 0; xs--) |
| 1169 | for (xs = (width - 1); xs >= 0; xs--) |
| 1085 | 1170 | { |
| 1086 | 1171 | if ((x + (count << 3) < SNES_SCR_WIDTH)) |
| 1087 | 1172 | { |
| r7539 | r7540 | |
| 1092 | 1177 | } |
| 1093 | 1178 | else |
| 1094 | 1179 | { |
| 1095 | | for (xs = 0; xs < snes_ppu.oam.size[size]; xs++) |
| 1180 | for (xs = 0; xs < width; xs++) |
| 1096 | 1181 | { |
| 1097 | 1182 | if ((x + (xs << 3) < SNES_SCR_WIDTH)) |
| 1098 | 1183 | { |
| r7539 | r7540 | |
| 1252 | 1337 | |
| 1253 | 1338 | static void snes_draw_screens( UINT16 curline ) |
| 1254 | 1339 | { |
| 1340 | snes_oam_list_build(); |
| 1341 | |
| 1255 | 1342 | switch (snes_ppu.mode) |
| 1256 | 1343 | { |
| 1257 | 1344 | case 0: snes_update_mode_0(curline); break; /* Mode 0 */ |
| r7539 | r7540 | |
| 1264 | 1351 | case 7: snes_update_mode_7(curline); break; /* Mode 7 - Supports direct colour */ |
| 1265 | 1352 | } |
| 1266 | 1353 | } |
| 1267 | | |
| 1354 | |
| 1268 | 1355 | /********************************************* |
| 1269 | 1356 | * snes_update_windowmasks() |
| 1270 | 1357 | * |
| r7539 | r7540 | |
| 1494 | 1581 | { |
| 1495 | 1582 | int y; |
| 1496 | 1583 | |
| 1584 | snes_update_obsel(); |
| 1585 | |
| 1497 | 1586 | /*NTSC SNES draw range is 1-225. */ |
| 1498 | 1587 | for (y = cliprect->min_y; y <= cliprect->max_y; y++) |
| 1588 | { |
| 1499 | 1589 | snes_refresh_scanline(screen->machine, bitmap, y + 1); |
| 1590 | snes_update_obsel(); |
| 1591 | } |
| 1500 | 1592 | return 0; |
| 1501 | 1593 | } |
| 1502 | 1594 | |
| r7539 | r7540 | |
| 1617 | 1709 | snes_ram[BG4SC] & 0x3, |
| 1618 | 1710 | (snes_ram[BG4SC] & 0xfc) << 9, |
| 1619 | 1711 | snes_ppu.layer[SNES_BG4].charmap << 13 ); |
| 1620 | | logerror("%sO %s%s%s%s%s%c%s%s%d%d %4X", |
| 1712 | logerror("%sO %s%s%s%s%s%c%s%s %4X", |
| 1621 | 1713 | debug_options.bg_disabled[4]?" ":"*", |
| 1622 | 1714 | (snes_ram[TM] & 0x10)?"M":" ", |
| 1623 | 1715 | (snes_ram[TS] & 0x10)?"S":" ", |
| r7539 | r7540 | |
| 1627 | 1719 | WINLOGIC[(snes_ram[WOBJLOG] & 0x3)], |
| 1628 | 1720 | (snes_ram[WOBJSEL] & 0x2)?((snes_ram[WOBJSEL] & 0x1)?"o":"i"):" ", |
| 1629 | 1721 | (snes_ram[WOBJSEL] & 0x8)?((snes_ram[WOBJSEL] & 0x4)?"o":"i"):" ", |
| 1630 | | snes_ppu.oam.size[0], snes_ppu.oam.size[1], |
| 1631 | 1722 | snes_ppu.layer[SNES_OAM].charmap << 13 ); |
| 1632 | 1723 | logerror("%sB %s %c%s%s", |
| 1633 | 1724 | debug_options.bg_disabled[5]?" ":"*", |