dsp2.cpp
1 /*****************************************************************************\ 2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. 3 This file is licensed under the Snes9x License. 4 For further information, consult the LICENSE file in the root directory. 5 \*****************************************************************************/ 6 7 #include "snes9x.h" 8 #include "memory.h" 9 10 static void DSP2_Op01 (void); 11 static void DSP2_Op03 (void); 12 static void DSP2_Op05 (void); 13 static void DSP2_Op06 (void); 14 static void DSP2_Op09 (void); 15 static void DSP2_Op0D (void); 16 17 18 // convert bitmap to bitplane tile 19 static void DSP2_Op01 (void) 20 { 21 // Op01 size is always 32 bytes input and output 22 // The hardware does strange things if you vary the size 23 24 uint8 c0, c1, c2, c3; 25 uint8 *p1 = DSP2.parameters; 26 uint8 *p2a = DSP2.output; 27 uint8 *p2b = DSP2.output + 16; // halfway 28 29 // Process 8 blocks of 4 bytes each 30 31 for (int j = 0; j < 8; j++) 32 { 33 c0 = *p1++; 34 c1 = *p1++; 35 c2 = *p1++; 36 c3 = *p1++; 37 38 *p2a++ = (c0 & 0x10) << 3 | 39 (c0 & 0x01) << 6 | 40 (c1 & 0x10) << 1 | 41 (c1 & 0x01) << 4 | 42 (c2 & 0x10) >> 1 | 43 (c2 & 0x01) << 2 | 44 (c3 & 0x10) >> 3 | 45 (c3 & 0x01); 46 47 *p2a++ = (c0 & 0x20) << 2 | 48 (c0 & 0x02) << 5 | 49 (c1 & 0x20) | 50 (c1 & 0x02) << 3 | 51 (c2 & 0x20) >> 2 | 52 (c2 & 0x02) << 1 | 53 (c3 & 0x20) >> 4 | 54 (c3 & 0x02) >> 1; 55 56 *p2b++ = (c0 & 0x40) << 1 | 57 (c0 & 0x04) << 4 | 58 (c1 & 0x40) >> 1 | 59 (c1 & 0x04) << 2 | 60 (c2 & 0x40) >> 3 | 61 (c2 & 0x04) | 62 (c3 & 0x40) >> 5 | 63 (c3 & 0x04) >> 2; 64 65 *p2b++ = (c0 & 0x80) | 66 (c0 & 0x08) << 3 | 67 (c1 & 0x80) >> 2 | 68 (c1 & 0x08) << 1 | 69 (c2 & 0x80) >> 4 | 70 (c2 & 0x08) >> 1 | 71 (c3 & 0x80) >> 6 | 72 (c3 & 0x08) >> 3; 73 } 74 } 75 76 // set transparent color 77 static void DSP2_Op03 (void) 78 { 79 DSP2.Op05Transparent = DSP2.parameters[0]; 80 } 81 82 // replace bitmap using transparent color 83 static void DSP2_Op05 (void) 84 { 85 // Overlay bitmap with transparency. 86 // Input: 87 // 88 // Bitmap 1: i[0] <=> i[size-1] 89 // Bitmap 2: i[size] <=> i[2*size-1] 90 // 91 // Output: 92 // 93 // Bitmap 3: o[0] <=> o[size-1] 94 // 95 // Processing: 96 // 97 // Process all 4-bit pixels (nibbles) in the bitmap 98 // 99 // if ( BM2_pixel == transparent_color ) 100 // pixelout = BM1_pixel 101 // else 102 // pixelout = BM2_pixel 103 104 // The max size bitmap is limited to 255 because the size parameter is a byte 105 // I think size=0 is an error. The behavior of the chip on size=0 is to 106 // return the last value written to DR if you read DR on Op05 with 107 // size = 0. I don't think it's worth implementing this quirk unless it's 108 // proven necessary. 109 110 uint8 color; 111 uint8 c1, c2; 112 uint8 *p1 = DSP2.parameters; 113 uint8 *p2 = DSP2.parameters + DSP2.Op05Len; 114 uint8 *p3 = DSP2.output; 115 116 color = DSP2.Op05Transparent & 0x0f; 117 118 for (int n = 0; n < DSP2.Op05Len; n++) 119 { 120 c1 = *p1++; 121 c2 = *p2++; 122 *p3++ = (((c2 >> 4) == color) ? c1 & 0xf0: c2 & 0xf0) | (((c2 & 0x0f) == color) ? c1 & 0x0f: c2 & 0x0f); 123 } 124 } 125 126 // reverse bitmap 127 static void DSP2_Op06 (void) 128 { 129 // Input: 130 // size 131 // bitmap 132 133 for (int i = 0, j = DSP2.Op06Len - 1; i < DSP2.Op06Len; i++, j--) 134 DSP2.output[j] = (DSP2.parameters[i] << 4) | (DSP2.parameters[i] >> 4); 135 } 136 137 // multiply 138 static void DSP2_Op09 (void) 139 { 140 DSP2.Op09Word1 = DSP2.parameters[0] | (DSP2.parameters[1] << 8); 141 DSP2.Op09Word2 = DSP2.parameters[2] | (DSP2.parameters[3] << 8); 142 143 uint32 temp = DSP2.Op09Word1 * DSP2.Op09Word2; 144 DSP2.output[0] = temp & 0xFF; 145 DSP2.output[1] = (temp >> 8) & 0xFF; 146 DSP2.output[2] = (temp >> 16) & 0xFF; 147 DSP2.output[3] = (temp >> 24) & 0xFF; 148 } 149 150 // scale bitmap 151 static void DSP2_Op0D (void) 152 { 153 // Bit accurate hardware algorithm - uses fixed point math 154 // This should match the DSP2 Op0D output exactly 155 // I wouldn't recommend using this unless you're doing hardware debug. 156 // In some situations it has small visual artifacts that 157 // are not readily apparent on a TV screen but show up clearly 158 // on a monitor. Use Overload's scaling instead. 159 // This is for hardware verification testing. 160 // 161 // One note: the HW can do odd byte scaling but since we divide 162 // by two to get the count of bytes this won't work well for 163 // odd byte scaling (in any of the current algorithm implementations). 164 // So far I haven't seen Dungeon Master use it. 165 // If it does we can adjust the parameters and code to work with it 166 167 uint32 multiplier; // Any size int >= 32-bits 168 uint32 pixloc; // match size of multiplier 169 uint8 pixelarray[512]; 170 171 if (DSP2.Op0DInLen <= DSP2.Op0DOutLen) 172 multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1 173 else 174 multiplier = (DSP2.Op0DInLen << 17) / ((DSP2.Op0DOutLen << 1) + 1); 175 176 pixloc = 0; 177 178 for (int i = 0; i < DSP2.Op0DOutLen * 2; i++) 179 { 180 int32 j = pixloc >> 16; 181 182 if (j & 1) 183 pixelarray[i] = DSP2.parameters[j >> 1] & 0x0f; 184 else 185 pixelarray[i] = (DSP2.parameters[j >> 1] & 0xf0) >> 4; 186 187 pixloc += multiplier; 188 } 189 190 for (int i = 0; i < DSP2.Op0DOutLen; i++) 191 DSP2.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1]; 192 } 193 194 /* 195 static void DSP2_Op0D (void) 196 { 197 // Overload's algorithm - use this unless doing hardware testing 198 199 // One note: the HW can do odd byte scaling but since we divide 200 // by two to get the count of bytes this won't work well for 201 // odd byte scaling (in any of the current algorithm implementations). 202 // So far I haven't seen Dungeon Master use it. 203 // If it does we can adjust the parameters and code to work with it 204 205 int32 pixel_offset; 206 uint8 pixelarray[512]; 207 208 for (int i = 0; i < DSP2.Op0DOutLen * 2; i++) 209 { 210 pixel_offset = (i * DSP2.Op0DInLen) / DSP2.Op0DOutLen; 211 212 if ((pixel_offset & 1) == 0) 213 pixelarray[i] = DSP2.parameters[pixel_offset >> 1] >> 4; 214 else 215 pixelarray[i] = DSP2.parameters[pixel_offset >> 1] & 0x0f; 216 } 217 218 for (int i = 0; i < DSP2.Op0DOutLen; i++) 219 DSP2.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1]; 220 } 221 */ 222 223 void DSP2SetByte (uint8 byte, uint16 address) 224 { 225 if ((address & 0xf000) == 0x6000 || (address >= 0x8000 && address < 0xc000)) 226 { 227 if (DSP2.waiting4command) 228 { 229 DSP2.command = byte; 230 DSP2.in_index = 0; 231 DSP2.waiting4command = FALSE; 232 233 switch (byte) 234 { 235 case 0x01: DSP2.in_count = 32; break; 236 case 0x03: DSP2.in_count = 1; break; 237 case 0x05: DSP2.in_count = 1; break; 238 case 0x06: DSP2.in_count = 1; break; 239 case 0x09: DSP2.in_count = 4; break; 240 case 0x0D: DSP2.in_count = 2; break; 241 default: 242 #ifdef DEBUGGER 243 //printf("Op%02X\n", byte); 244 #endif 245 case 0x0f: DSP2.in_count = 0; break; 246 } 247 } 248 else 249 { 250 DSP2.parameters[DSP2.in_index] = byte; 251 DSP2.in_index++; 252 } 253 254 if (DSP2.in_count == DSP2.in_index) 255 { 256 DSP2.waiting4command = TRUE; 257 DSP2.out_index = 0; 258 259 switch (DSP2.command) 260 { 261 case 0x01: 262 DSP2.out_count = 32; 263 DSP2_Op01(); 264 break; 265 266 case 0x03: 267 DSP2_Op03(); 268 break; 269 270 case 0x05: 271 if (DSP2.Op05HasLen) 272 { 273 DSP2.Op05HasLen = FALSE; 274 DSP2.out_count = DSP2.Op05Len; 275 DSP2_Op05(); 276 } 277 else 278 { 279 DSP2.Op05Len = DSP2.parameters[0]; 280 DSP2.in_index = 0; 281 DSP2.in_count = 2 * DSP2.Op05Len; 282 DSP2.Op05HasLen = TRUE; 283 if (byte) 284 DSP2.waiting4command = FALSE; 285 } 286 287 break; 288 289 case 0x06: 290 if (DSP2.Op06HasLen) 291 { 292 DSP2.Op06HasLen = FALSE; 293 DSP2.out_count = DSP2.Op06Len; 294 DSP2_Op06(); 295 } 296 else 297 { 298 DSP2.Op06Len = DSP2.parameters[0]; 299 DSP2.in_index = 0; 300 DSP2.in_count = DSP2.Op06Len; 301 DSP2.Op06HasLen = TRUE; 302 if (byte) 303 DSP2.waiting4command = FALSE; 304 } 305 306 break; 307 308 case 0x09: 309 DSP2.out_count = 4; 310 DSP2_Op09(); 311 break; 312 313 case 0x0D: 314 if (DSP2.Op0DHasLen) 315 { 316 DSP2.Op0DHasLen = FALSE; 317 DSP2.out_count = DSP2.Op0DOutLen; 318 DSP2_Op0D(); 319 } 320 else 321 { 322 DSP2.Op0DInLen = DSP2.parameters[0]; 323 DSP2.Op0DOutLen = DSP2.parameters[1]; 324 DSP2.in_index = 0; 325 DSP2.in_count = (DSP2.Op0DInLen + 1) >> 1; 326 DSP2.Op0DHasLen = TRUE; 327 if (byte) 328 DSP2.waiting4command = FALSE; 329 } 330 331 break; 332 333 case 0x0f: 334 default: 335 break; 336 } 337 } 338 } 339 } 340 341 uint8 DSP2GetByte (uint16 address) 342 { 343 uint8 t; 344 345 if ((address & 0xf000) == 0x6000 || (address >= 0x8000 && address < 0xc000)) 346 { 347 if (DSP2.out_count) 348 { 349 t = (uint8) DSP2.output[DSP2.out_index]; 350 DSP2.out_index++; 351 if (DSP2.out_count == DSP2.out_index) 352 DSP2.out_count = 0; 353 } 354 else 355 t = 0xff; 356 } 357 else 358 t = 0x80; 359 360 return (t); 361 }