trunk/src/mess/machine/snessdd1.c
| r0 | r21590 | |
| 1 | /*************************************************************************** |
| 2 | |
| 3 | snessdd1.c |
| 4 | |
| 5 | File to handle emulation of the SNES "S-DD1" add-on chip. |
| 6 | |
| 7 | Based on Andreas Naive Public Domain code. |
| 8 | |
| 9 | ***************************************************************************/ |
| 10 | |
| 11 | |
| 12 | #define SSD1_ADD(addr)\ |
| 13 | mmc[(addr >> 20) & 3] + (addr & 0x0fffff) |
| 14 | |
| 15 | class SDD1_IM //Input Manager |
| 16 | { |
| 17 | public: |
| 18 | SDD1_IM() {} |
| 19 | |
| 20 | UINT32 m_byte_ptr; |
| 21 | UINT8 m_bit_count; |
| 22 | |
| 23 | void IM_prepareDecomp(UINT32 in_buf); |
| 24 | UINT8 IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len); |
| 25 | }; |
| 26 | |
| 27 | void SDD1_IM::IM_prepareDecomp(UINT32 in_buf) |
| 28 | { |
| 29 | m_byte_ptr = in_buf; |
| 30 | m_bit_count = 4; |
| 31 | } |
| 32 | |
| 33 | UINT8 SDD1_IM::IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len) |
| 34 | { |
| 35 | UINT8 codeword = ROM[SSD1_ADD(m_byte_ptr)] << m_bit_count; |
| 36 | |
| 37 | ++m_bit_count; |
| 38 | |
| 39 | if (codeword & 0x80) |
| 40 | { |
| 41 | codeword |= ROM[SSD1_ADD((m_byte_ptr + 1))] >> (9 - m_bit_count); |
| 42 | m_bit_count += code_len; |
| 43 | } |
| 44 | |
| 45 | if (m_bit_count & 0x08) |
| 46 | { |
| 47 | m_byte_ptr++; |
| 48 | m_bit_count &= 0x07; |
| 49 | } |
| 50 | |
| 51 | return codeword; |
| 52 | } |
| 53 | |
| 54 | class SDD1_GCD //Golomb-Code Decoder |
| 55 | { |
| 56 | public: |
| 57 | SDD1_GCD(SDD1_IM* associatedIM) |
| 58 | : m_IM(associatedIM) { } |
| 59 | |
| 60 | SDD1_IM* m_IM; |
| 61 | |
| 62 | void GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind); |
| 63 | }; |
| 64 | |
| 65 | void SDD1_GCD::GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind) |
| 66 | { |
| 67 | const UINT8 run_count[] = |
| 68 | { |
| 69 | 0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00, |
| 70 | 0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00, |
| 71 | 0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01, |
| 72 | 0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00, |
| 73 | 0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03, |
| 74 | 0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01, |
| 75 | 0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02, |
| 76 | 0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00, |
| 77 | 0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07, |
| 78 | 0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03, |
| 79 | 0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05, |
| 80 | 0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01, |
| 81 | 0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06, |
| 82 | 0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02, |
| 83 | 0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04, |
| 84 | 0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00, |
| 85 | 0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f, |
| 86 | 0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07, |
| 87 | 0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b, |
| 88 | 0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03, |
| 89 | 0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d, |
| 90 | 0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05, |
| 91 | 0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09, |
| 92 | 0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01, |
| 93 | 0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e, |
| 94 | 0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06, |
| 95 | 0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a, |
| 96 | 0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02, |
| 97 | 0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c, |
| 98 | 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, |
| 99 | 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, |
| 100 | 0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00, |
| 101 | }; |
| 102 | |
| 103 | UINT8 codeword = m_IM->IM_getCodeword(ROM, mmc, code_num); |
| 104 | |
| 105 | if (codeword & 0x80) |
| 106 | { |
| 107 | *LPSind = 1; |
| 108 | *MPScount = run_count[codeword >> (code_num ^ 0x07)]; |
| 109 | } |
| 110 | else |
| 111 | { |
| 112 | *MPScount = (1 << code_num); |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | class SDD1_BG // Bits Generator |
| 117 | { |
| 118 | public: |
| 119 | SDD1_BG(SDD1_GCD* associatedGCD, UINT8 code) |
| 120 | : m_code_num(code), |
| 121 | m_GCD(associatedGCD) { } |
| 122 | |
| 123 | UINT8 m_code_num; |
| 124 | UINT8 m_MPScount; |
| 125 | UINT8 m_LPSind; |
| 126 | SDD1_GCD* m_GCD; |
| 127 | |
| 128 | void BG_prepareDecomp(); |
| 129 | UINT8 BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun); |
| 130 | } ; |
| 131 | |
| 132 | void SDD1_BG::BG_prepareDecomp() |
| 133 | { |
| 134 | m_MPScount = 0; |
| 135 | m_LPSind = 0; |
| 136 | } |
| 137 | |
| 138 | UINT8 SDD1_BG::BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun) |
| 139 | { |
| 140 | UINT8 bit; |
| 141 | |
| 142 | if (!(m_MPScount || m_LPSind)) |
| 143 | { |
| 144 | m_GCD->GCD_getRunCount(ROM, mmc, m_code_num, &(m_MPScount), &(m_LPSind)); |
| 145 | } |
| 146 | |
| 147 | if (m_MPScount) |
| 148 | { |
| 149 | bit = 0; |
| 150 | m_MPScount--; |
| 151 | } |
| 152 | else |
| 153 | { |
| 154 | bit = 1; |
| 155 | m_LPSind = 0; |
| 156 | } |
| 157 | |
| 158 | if (m_MPScount || m_LPSind) |
| 159 | { |
| 160 | (*endOfRun) = 0; |
| 161 | } |
| 162 | else |
| 163 | { |
| 164 | (*endOfRun) = 1; |
| 165 | } |
| 166 | |
| 167 | return bit; |
| 168 | } |
| 169 | |
| 170 | |
| 171 | struct SDD1_PEM_state |
| 172 | { |
| 173 | UINT8 code_num; |
| 174 | UINT8 nextIfMPS; |
| 175 | UINT8 nextIfLPS; |
| 176 | }; |
| 177 | |
| 178 | static const SDD1_PEM_state PEM_evolution_table[33] = |
| 179 | { |
| 180 | { 0,25,25}, |
| 181 | { 0, 2, 1}, |
| 182 | { 0, 3, 1}, |
| 183 | { 0, 4, 2}, |
| 184 | { 0, 5, 3}, |
| 185 | { 1, 6, 4}, |
| 186 | { 1, 7, 5}, |
| 187 | { 1, 8, 6}, |
| 188 | { 1, 9, 7}, |
| 189 | { 2,10, 8}, |
| 190 | { 2,11, 9}, |
| 191 | { 2,12,10}, |
| 192 | { 2,13,11}, |
| 193 | { 3,14,12}, |
| 194 | { 3,15,13}, |
| 195 | { 3,16,14}, |
| 196 | { 3,17,15}, |
| 197 | { 4,18,16}, |
| 198 | { 4,19,17}, |
| 199 | { 5,20,18}, |
| 200 | { 5,21,19}, |
| 201 | { 6,22,20}, |
| 202 | { 6,23,21}, |
| 203 | { 7,24,22}, |
| 204 | { 7,24,23}, |
| 205 | { 0,26, 1}, |
| 206 | { 1,27, 2}, |
| 207 | { 2,28, 4}, |
| 208 | { 3,29, 8}, |
| 209 | { 4,30,12}, |
| 210 | { 5,31,16}, |
| 211 | { 6,32,18}, |
| 212 | { 7,24,22} |
| 213 | }; |
| 214 | |
| 215 | struct SDD1_PEM_ContextInfo |
| 216 | { |
| 217 | UINT8 status; |
| 218 | UINT8 MPS; |
| 219 | }; |
| 220 | |
| 221 | class SDD1_PEM //Probability Estimation Module |
| 222 | { |
| 223 | public: |
| 224 | SDD1_PEM( |
| 225 | SDD1_BG* associatedBG0, SDD1_BG* associatedBG1, |
| 226 | SDD1_BG* associatedBG2, SDD1_BG* associatedBG3, |
| 227 | SDD1_BG* associatedBG4, SDD1_BG* associatedBG5, |
| 228 | SDD1_BG* associatedBG6, SDD1_BG* associatedBG7) |
| 229 | { |
| 230 | m_BG[0] = associatedBG0; |
| 231 | m_BG[1] = associatedBG1; |
| 232 | m_BG[2] = associatedBG2; |
| 233 | m_BG[3] = associatedBG3; |
| 234 | m_BG[4] = associatedBG4; |
| 235 | m_BG[5] = associatedBG5; |
| 236 | m_BG[6] = associatedBG6; |
| 237 | m_BG[7] = associatedBG7; |
| 238 | } |
| 239 | |
| 240 | SDD1_PEM_ContextInfo m_contextInfo[32]; |
| 241 | SDD1_BG* m_BG[8]; |
| 242 | |
| 243 | void PEM_prepareDecomp(); |
| 244 | UINT8 PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context); |
| 245 | } ; |
| 246 | |
| 247 | void SDD1_PEM::PEM_prepareDecomp() |
| 248 | { |
| 249 | for (int i = 0; i < 32; i++) |
| 250 | { |
| 251 | m_contextInfo[i].status = 0; |
| 252 | m_contextInfo[i].MPS = 0; |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | UINT8 SDD1_PEM::PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context) |
| 257 | { |
| 258 | UINT8 endOfRun; |
| 259 | UINT8 bit; |
| 260 | |
| 261 | SDD1_PEM_ContextInfo *pContInfo = &(m_contextInfo)[context]; |
| 262 | UINT8 currStatus = pContInfo->status; |
| 263 | const SDD1_PEM_state* pState = &(PEM_evolution_table[currStatus]); |
| 264 | UINT8 currentMPS = pContInfo->MPS; |
| 265 | |
| 266 | bit = m_BG[pState->code_num]->BG_getBit(ROM, mmc, &endOfRun); |
| 267 | |
| 268 | if (endOfRun) |
| 269 | { |
| 270 | if (bit) |
| 271 | { |
| 272 | if (!(currStatus & 0xfe)) |
| 273 | { |
| 274 | (pContInfo->MPS) ^= 0x01; |
| 275 | } |
| 276 | pContInfo->status = pState->nextIfLPS; |
| 277 | } |
| 278 | else |
| 279 | { |
| 280 | pContInfo->status = pState->nextIfMPS; |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | return bit ^ currentMPS; |
| 285 | } |
| 286 | |
| 287 | class SDD1_CM |
| 288 | { |
| 289 | public: |
| 290 | SDD1_CM(SDD1_PEM* associatedPEM) |
| 291 | : m_PEM(associatedPEM) { } |
| 292 | |
| 293 | UINT8 m_bitplanesInfo; |
| 294 | UINT8 m_contextBitsInfo; |
| 295 | UINT8 m_bit_number; |
| 296 | UINT8 m_currBitplane; |
| 297 | UINT16 m_prevBitplaneBits[8]; |
| 298 | SDD1_PEM* m_PEM; |
| 299 | |
| 300 | void CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte); |
| 301 | UINT8 CM_getBit(UINT8 *ROM, UINT32 *mmc); |
| 302 | } ; |
| 303 | |
| 304 | void SDD1_CM::CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte) |
| 305 | { |
| 306 | INT32 i = 0; |
| 307 | m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0; |
| 308 | m_contextBitsInfo = ROM[SSD1_ADD(first_byte)] & 0x30; |
| 309 | m_bit_number = 0; |
| 310 | for (i = 0; i < 8; i++) |
| 311 | { |
| 312 | m_prevBitplaneBits[i] = 0; |
| 313 | } |
| 314 | switch (m_bitplanesInfo) |
| 315 | { |
| 316 | case 0x00: |
| 317 | m_currBitplane = 1; |
| 318 | break; |
| 319 | case 0x40: |
| 320 | m_currBitplane = 7; |
| 321 | break; |
| 322 | case 0x80: |
| 323 | m_currBitplane = 3; |
| 324 | break; |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | UINT8 SDD1_CM::CM_getBit(UINT8 *ROM, UINT32 *mmc) |
| 329 | { |
| 330 | UINT8 currContext; |
| 331 | UINT16 *context_bits; |
| 332 | UINT8 bit = 0; |
| 333 | |
| 334 | switch (m_bitplanesInfo) |
| 335 | { |
| 336 | case 0x00: |
| 337 | m_currBitplane ^= 0x01; |
| 338 | break; |
| 339 | case 0x40: |
| 340 | m_currBitplane ^= 0x01; |
| 341 | if (!(m_bit_number & 0x7f)) |
| 342 | m_currBitplane = ((m_currBitplane + 2) & 0x07); |
| 343 | break; |
| 344 | case 0x80: |
| 345 | m_currBitplane ^= 0x01; |
| 346 | if (!(m_bit_number & 0x7f)) |
| 347 | m_currBitplane ^= 0x02; |
| 348 | break; |
| 349 | case 0xc0: |
| 350 | m_currBitplane = m_bit_number & 0x07; |
| 351 | break; |
| 352 | } |
| 353 | |
| 354 | context_bits = &(m_prevBitplaneBits)[m_currBitplane]; |
| 355 | |
| 356 | currContext = (m_currBitplane & 0x01) << 4; |
| 357 | switch (m_contextBitsInfo) |
| 358 | { |
| 359 | case 0x00: |
| 360 | currContext |= ((*context_bits & 0x01c0) >> 5) | (*context_bits & 0x0001); |
| 361 | break; |
| 362 | case 0x10: |
| 363 | currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0001); |
| 364 | break; |
| 365 | case 0x20: |
| 366 | currContext |= ((*context_bits & 0x00c0) >> 5) | (*context_bits & 0x0001); |
| 367 | break; |
| 368 | case 0x30: |
| 369 | currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0003); |
| 370 | break; |
| 371 | } |
| 372 | |
| 373 | bit = m_PEM->PEM_getBit(ROM, mmc, currContext); |
| 374 | |
| 375 | *context_bits <<= 1; |
| 376 | *context_bits |= bit; |
| 377 | |
| 378 | m_bit_number++; |
| 379 | |
| 380 | return bit; |
| 381 | } |
| 382 | |
| 383 | class SDD1_OL |
| 384 | { |
| 385 | public: |
| 386 | SDD1_OL(SDD1_CM* associatedCM) |
| 387 | : m_CM(associatedCM) { } |
| 388 | |
| 389 | UINT8 m_bitplanesInfo; |
| 390 | UINT16 m_length; |
| 391 | UINT8* m_buffer; |
| 392 | SDD1_CM* m_CM; |
| 393 | |
| 394 | void OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf); |
| 395 | void OL_launch(UINT8 *ROM, UINT32 *mmc); |
| 396 | } ; |
| 397 | |
| 398 | void SDD1_OL::OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf) |
| 399 | { |
| 400 | m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0; |
| 401 | m_length = out_len; |
| 402 | m_buffer = out_buf; |
| 403 | } |
| 404 | |
| 405 | void SDD1_OL::OL_launch(UINT8 *ROM, UINT32 *mmc) |
| 406 | { |
| 407 | UINT8 i; |
| 408 | UINT8 register1 = 0, register2 = 0; |
| 409 | |
| 410 | switch (m_bitplanesInfo) |
| 411 | { |
| 412 | case 0x00: |
| 413 | case 0x40: |
| 414 | case 0x80: |
| 415 | i = 1; |
| 416 | do |
| 417 | { // if length == 0, we output 2^16 bytes |
| 418 | if (!i) |
| 419 | { |
| 420 | *(m_buffer++) = register2; |
| 421 | i = ~i; |
| 422 | } |
| 423 | else |
| 424 | { |
| 425 | for (register1 = register2 = 0, i = 0x80; i; i >>= 1) |
| 426 | { |
| 427 | if (m_CM->CM_getBit(ROM, mmc)) |
| 428 | register1 |= i; |
| 429 | |
| 430 | if (m_CM->CM_getBit(ROM, mmc)) |
| 431 | register2 |= i; |
| 432 | } |
| 433 | *(m_buffer++) = register1; |
| 434 | } |
| 435 | } while (--(m_length)); |
| 436 | break; |
| 437 | case 0xc0: |
| 438 | do |
| 439 | { |
| 440 | for (register1 = 0, i = 0x01; i; i <<= 1) |
| 441 | { |
| 442 | if (m_CM->CM_getBit(ROM, mmc)) |
| 443 | { |
| 444 | register1 |= i; |
| 445 | } |
| 446 | } |
| 447 | *(m_buffer++) = register1; |
| 448 | } while (--(m_length)); |
| 449 | break; |
| 450 | } |
| 451 | } |
| 452 | |
| 453 | class SDD1emu |
| 454 | { |
| 455 | public: |
| 456 | SDD1emu(running_machine &machine); |
| 457 | |
| 458 | running_machine &machine() const { return m_machine; } |
| 459 | |
| 460 | SDD1_IM* m_IM; |
| 461 | SDD1_GCD* m_GCD; |
| 462 | SDD1_BG* m_BG0; SDD1_BG* m_BG1; SDD1_BG* m_BG2; SDD1_BG* m_BG3; |
| 463 | SDD1_BG* m_BG4; SDD1_BG* m_BG5; SDD1_BG* m_BG6; SDD1_BG* m_BG7; |
| 464 | SDD1_PEM* m_PEM; |
| 465 | SDD1_CM* m_CM; |
| 466 | SDD1_OL* m_OL; |
| 467 | |
| 468 | void SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf); |
| 469 | |
| 470 | private: |
| 471 | running_machine& m_machine; |
| 472 | }; |
| 473 | |
| 474 | SDD1emu::SDD1emu(running_machine &machine) |
| 475 | : m_machine(machine) |
| 476 | { |
| 477 | m_IM = auto_alloc(machine, SDD1_IM()); |
| 478 | m_GCD = auto_alloc(machine, SDD1_GCD(m_IM)); |
| 479 | m_BG0 = auto_alloc(machine, SDD1_BG(m_GCD, 0)); |
| 480 | m_BG1 = auto_alloc(machine, SDD1_BG(m_GCD, 1)); |
| 481 | m_BG2 = auto_alloc(machine, SDD1_BG(m_GCD, 2)); |
| 482 | m_BG3 = auto_alloc(machine, SDD1_BG(m_GCD, 3)); |
| 483 | m_BG4 = auto_alloc(machine, SDD1_BG(m_GCD, 4)); |
| 484 | m_BG5 = auto_alloc(machine, SDD1_BG(m_GCD, 5)); |
| 485 | m_BG6 = auto_alloc(machine, SDD1_BG(m_GCD, 6)); |
| 486 | m_BG7 = auto_alloc(machine, SDD1_BG(m_GCD, 7)); |
| 487 | m_PEM = auto_alloc(machine, SDD1_PEM(m_BG0, m_BG1, m_BG2, m_BG3, |
| 488 | m_BG4, m_BG5, m_BG6, m_BG7)); |
| 489 | m_CM = auto_alloc(machine, SDD1_CM(m_PEM)); |
| 490 | m_OL = auto_alloc(machine, SDD1_OL(m_CM)); |
| 491 | } |
| 492 | |
| 493 | void SDD1emu::SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf) |
| 494 | { |
| 495 | m_IM->IM_prepareDecomp(in_buf); |
| 496 | m_BG0->BG_prepareDecomp(); |
| 497 | m_BG1->BG_prepareDecomp(); |
| 498 | m_BG2->BG_prepareDecomp(); |
| 499 | m_BG3->BG_prepareDecomp(); |
| 500 | m_BG4->BG_prepareDecomp(); |
| 501 | m_BG5->BG_prepareDecomp(); |
| 502 | m_BG6->BG_prepareDecomp(); |
| 503 | m_BG7->BG_prepareDecomp(); |
| 504 | m_PEM->PEM_prepareDecomp(); |
| 505 | m_CM->CM_prepareDecomp(ROM, mmc, in_buf); |
| 506 | m_OL->OL_prepareDecomp(ROM, mmc, in_buf, out_len, out_buf); |
| 507 | |
| 508 | m_OL->OL_launch(ROM, mmc); |
| 509 | } |
| 510 | |
| 511 | struct snes_sdd1_t |
| 512 | { |
| 513 | UINT8 sdd1_enable; // channel bit-mask |
| 514 | UINT8 xfer_enable; // channel bit-mask |
| 515 | UINT32 mmc[4]; // memory map controller ROM indices |
| 516 | |
| 517 | struct |
| 518 | { |
| 519 | UINT32 addr; // $43x2-$43x4 -- DMA transfer address |
| 520 | UINT16 size; // $43x5-$43x6 -- DMA transfer size |
| 521 | } dma[8]; |
| 522 | |
| 523 | SDD1emu* sdd1emu; |
| 524 | struct |
| 525 | { |
| 526 | UINT8 *data; // pointer to decompressed S-DD1 data (65536 bytes) |
| 527 | UINT16 offset; // read index into S-DD1 decompression buffer |
| 528 | UINT32 size; // length of data buffer; reads decrement counter, set ready to false at 0 |
| 529 | UINT8 ready; // 1 when data[] is valid; 0 to invoke sdd1emu.decompress() |
| 530 | } buffer; |
| 531 | } ; |
| 532 | |
| 533 | static snes_sdd1_t snes_sdd1; |
| 534 | |
| 535 | void sdd1_init(running_machine& machine) |
| 536 | { |
| 537 | snes_sdd1.sdd1_enable = 0x00; |
| 538 | snes_sdd1.xfer_enable = 0x00; |
| 539 | |
| 540 | snes_sdd1.mmc[0] = 0 << 20; |
| 541 | snes_sdd1.mmc[1] = 1 << 20; |
| 542 | snes_sdd1.mmc[2] = 2 << 20; |
| 543 | snes_sdd1.mmc[3] = 3 << 20; |
| 544 | |
| 545 | for (int i = 0; i < 8; i++) |
| 546 | { |
| 547 | snes_sdd1.dma[i].addr = 0; |
| 548 | snes_sdd1.dma[i].size = 0; |
| 549 | } |
| 550 | |
| 551 | snes_sdd1.sdd1emu = auto_alloc(machine, SDD1emu(machine)); |
| 552 | |
| 553 | snes_sdd1.buffer.data = (UINT8*)auto_alloc_array(machine, UINT8, 0x10000); |
| 554 | snes_sdd1.buffer.ready = 0; |
| 555 | } |
| 556 | |
| 557 | UINT8 sdd1_mmio_read(address_space &space, UINT32 addr) |
| 558 | { |
| 559 | addr &= 0xffff; |
| 560 | |
| 561 | switch(addr) |
| 562 | { |
| 563 | case 0x4804: |
| 564 | return (snes_sdd1.mmc[0] >> 20) & 7; |
| 565 | case 0x4805: |
| 566 | return (snes_sdd1.mmc[1] >> 20) & 7; |
| 567 | case 0x4806: |
| 568 | return (snes_sdd1.mmc[2] >> 20) & 7; |
| 569 | case 0x4807: |
| 570 | return (snes_sdd1.mmc[3] >> 20) & 7; |
| 571 | } |
| 572 | |
| 573 | return snes_open_bus_r(space, 0); |
| 574 | } |
| 575 | |
| 576 | void sdd1_mmio_write(address_space &space, UINT32 addr, UINT8 data) |
| 577 | { |
| 578 | addr &= 0xffff; |
| 579 | |
| 580 | if ((addr & 0x4380) == 0x4300) |
| 581 | { |
| 582 | UINT8 channel = (addr >> 4) & 7; |
| 583 | switch(addr & 15) |
| 584 | { |
| 585 | case 2: |
| 586 | snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0xffff00) + (data << 0); |
| 587 | break; |
| 588 | case 3: |
| 589 | snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0xff00ff) + (data << 8); |
| 590 | break; |
| 591 | case 4: |
| 592 | snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0x00ffff) + (data << 16); |
| 593 | break; |
| 594 | |
| 595 | case 5: |
| 596 | snes_sdd1.dma[channel].size = (snes_sdd1.dma[channel].size & 0xff00) + (data << 0); |
| 597 | break; |
| 598 | case 6: |
| 599 | snes_sdd1.dma[channel].size = (snes_sdd1.dma[channel].size & 0x00ff) + (data << 8); |
| 600 | break; |
| 601 | } |
| 602 | return; |
| 603 | } |
| 604 | |
| 605 | switch(addr) |
| 606 | { |
| 607 | case 0x4800: |
| 608 | snes_sdd1.sdd1_enable = data; |
| 609 | break; |
| 610 | case 0x4801: |
| 611 | snes_sdd1.xfer_enable = data; |
| 612 | break; |
| 613 | |
| 614 | case 0x4804: |
| 615 | snes_sdd1.mmc[0] = (data & 7) << 20; |
| 616 | break; |
| 617 | case 0x4805: |
| 618 | snes_sdd1.mmc[1] = (data & 7) << 20; |
| 619 | break; |
| 620 | case 0x4806: |
| 621 | snes_sdd1.mmc[2] = (data & 7) << 20; |
| 622 | break; |
| 623 | case 0x4807: |
| 624 | snes_sdd1.mmc[3] = (data & 7) << 20; |
| 625 | break; |
| 626 | } |
| 627 | } |
| 628 | |
| 629 | UINT8 sdd1_read(running_machine& machine, UINT32 addr) |
| 630 | { |
| 631 | unsigned char *ROM = machine.root_device().memregion("cart")->base(); |
| 632 | |
| 633 | if (snes_sdd1.sdd1_enable & snes_sdd1.xfer_enable) |
| 634 | { |
| 635 | // at least one channel has S-DD1 decompression enabled... |
| 636 | for (int i = 0; i < 8; i++) |
| 637 | { |
| 638 | if (snes_sdd1.sdd1_enable & snes_sdd1.xfer_enable & (1 << i)) |
| 639 | { |
| 640 | // S-DD1 always uses fixed transfer mode, so address will not change during transfer |
| 641 | if ((addr + 0xc00000) == snes_sdd1.dma[i].addr) |
| 642 | { |
| 643 | UINT8 data; |
| 644 | if (!snes_sdd1.buffer.ready) |
| 645 | { |
| 646 | UINT8 temp; |
| 647 | // first byte read for channel performs full decompression. |
| 648 | // this really should stream byte-by-byte, but it's not necessary since the size is known |
| 649 | snes_sdd1.buffer.offset = 0; |
| 650 | snes_sdd1.buffer.size = snes_sdd1.dma[i].size ? snes_sdd1.dma[i].size : 65536; |
| 651 | |
| 652 | // sdd1emu calls this function; it needs to access uncompressed data; |
| 653 | // so temporarily disable decompression mode for decompress() call. |
| 654 | temp = snes_sdd1.sdd1_enable; |
| 655 | snes_sdd1.sdd1_enable = 0; |
| 656 | snes_sdd1.sdd1emu->SDD1emu_decompress(ROM, snes_sdd1.mmc, addr, snes_sdd1.buffer.size, snes_sdd1.buffer.data); |
| 657 | snes_sdd1.sdd1_enable = temp; |
| 658 | |
| 659 | snes_sdd1.buffer.ready = 1; |
| 660 | } |
| 661 | |
| 662 | // fetch a decompressed byte; once buffer is depleted, disable channel and invalidate buffer |
| 663 | data = snes_sdd1.buffer.data[(UINT16)snes_sdd1.buffer.offset++]; |
| 664 | if (snes_sdd1.buffer.offset >= snes_sdd1.buffer.size) |
| 665 | { |
| 666 | snes_sdd1.buffer.ready = 0; |
| 667 | snes_sdd1.xfer_enable &= ~(1 << i); |
| 668 | } |
| 669 | |
| 670 | return data; |
| 671 | } // address matched |
| 672 | } // channel enabled |
| 673 | } // channel loop |
| 674 | } // S-DD1 decompressor enabled |
| 675 | |
| 676 | return ROM[snes_sdd1.mmc[(addr >> 20) & 3] + (addr & 0x0fffff)]; |
| 677 | } |
trunk/src/mess/machine/snes7110.c
| r0 | r21590 | |
| 1 | /*************************************************************************** |
| 2 | |
| 3 | snes7110.c |
| 4 | |
| 5 | File to handle emulation of the SNES "SPC7110" add-on chip. |
| 6 | |
| 7 | Based on C++ implementation by Byuu in BSNES. |
| 8 | |
| 9 | Byuu's code is released under GNU General Public License |
| 10 | version 2 as published by the Free Software Foundation. |
| 11 | The implementation below is released under the MAME license |
| 12 | for use in MAME, MESS and derivatives by permission of the |
| 13 | author |
| 14 | |
| 15 | ***************************************************************************/ |
| 16 | |
| 17 | |
| 18 | #define SPC7110_DECOMP_BUFFER_SIZE 64 |
| 19 | |
| 20 | static const UINT8 spc7110_evolution_table[53][4] = |
| 21 | { |
| 22 | { 0x5a, 1, 1, 1 }, |
| 23 | { 0x25, 6, 2, 0 }, |
| 24 | { 0x11, 8, 3, 0 }, |
| 25 | { 0x08, 10, 4, 0 }, |
| 26 | { 0x03, 12, 5, 0 }, |
| 27 | { 0x01, 15, 5, 0 }, |
| 28 | |
| 29 | { 0x5a, 7, 7, 1 }, |
| 30 | { 0x3f, 19, 8, 0 }, |
| 31 | { 0x2c, 21, 9, 0 }, |
| 32 | { 0x20, 22, 10, 0 }, |
| 33 | { 0x17, 23, 11, 0 }, |
| 34 | { 0x11, 25, 12, 0 }, |
| 35 | { 0x0c, 26, 13, 0 }, |
| 36 | { 0x09, 28, 14, 0 }, |
| 37 | { 0x07, 29, 15, 0 }, |
| 38 | { 0x05, 31, 16, 0 }, |
| 39 | { 0x04, 32, 17, 0 }, |
| 40 | { 0x03, 34, 18, 0 }, |
| 41 | { 0x02, 35, 5, 0 }, |
| 42 | |
| 43 | { 0x5a, 20, 20, 1 }, |
| 44 | { 0x48, 39, 21, 0 }, |
| 45 | { 0x3a, 40, 22, 0 }, |
| 46 | { 0x2e, 42, 23, 0 }, |
| 47 | { 0x26, 44, 24, 0 }, |
| 48 | { 0x1f, 45, 25, 0 }, |
| 49 | { 0x19, 46, 26, 0 }, |
| 50 | { 0x15, 25, 27, 0 }, |
| 51 | { 0x11, 26, 28, 0 }, |
| 52 | { 0x0e, 26, 29, 0 }, |
| 53 | { 0x0b, 27, 30, 0 }, |
| 54 | { 0x09, 28, 31, 0 }, |
| 55 | { 0x08, 29, 32, 0 }, |
| 56 | { 0x07, 30, 33, 0 }, |
| 57 | { 0x05, 31, 34, 0 }, |
| 58 | { 0x04, 33, 35, 0 }, |
| 59 | { 0x04, 33, 36, 0 }, |
| 60 | { 0x03, 34, 37, 0 }, |
| 61 | { 0x02, 35, 38, 0 }, |
| 62 | { 0x02, 36, 5, 0 }, |
| 63 | |
| 64 | { 0x58, 39, 40, 1 }, |
| 65 | { 0x4d, 47, 41, 0 }, |
| 66 | { 0x43, 48, 42, 0 }, |
| 67 | { 0x3b, 49, 43, 0 }, |
| 68 | { 0x34, 50, 44, 0 }, |
| 69 | { 0x2e, 51, 45, 0 }, |
| 70 | { 0x29, 44, 46, 0 }, |
| 71 | { 0x25, 45, 24, 0 }, |
| 72 | |
| 73 | { 0x56, 47, 48, 1 }, |
| 74 | { 0x4f, 47, 49, 0 }, |
| 75 | { 0x47, 48, 50, 0 }, |
| 76 | { 0x41, 49, 51, 0 }, |
| 77 | { 0x3c, 50, 52, 0 }, |
| 78 | { 0x37, 51, 43, 0 }, |
| 79 | }; |
| 80 | |
| 81 | static const UINT8 spc7110_mode2_context_table[32][2] = |
| 82 | { |
| 83 | { 1, 2 }, |
| 84 | |
| 85 | { 3, 8 }, |
| 86 | { 13, 14 }, |
| 87 | |
| 88 | { 15, 16 }, |
| 89 | { 17, 18 }, |
| 90 | { 19, 20 }, |
| 91 | { 21, 22 }, |
| 92 | { 23, 24 }, |
| 93 | { 25, 26 }, |
| 94 | { 25, 26 }, |
| 95 | { 25, 26 }, |
| 96 | { 25, 26 }, |
| 97 | { 25, 26 }, |
| 98 | { 27, 28 }, |
| 99 | { 29, 30 }, |
| 100 | |
| 101 | { 31, 31 }, |
| 102 | { 31, 31 }, |
| 103 | { 31, 31 }, |
| 104 | { 31, 31 }, |
| 105 | { 31, 31 }, |
| 106 | { 31, 31 }, |
| 107 | { 31, 31 }, |
| 108 | { 31, 31 }, |
| 109 | { 31, 31 }, |
| 110 | { 31, 31 }, |
| 111 | { 31, 31 }, |
| 112 | { 31, 31 }, |
| 113 | { 31, 31 }, |
| 114 | { 31, 31 }, |
| 115 | { 31, 31 }, |
| 116 | { 31, 31 }, |
| 117 | |
| 118 | { 31, 31 }, |
| 119 | }; |
| 120 | |
| 121 | class SPC7110Decomp |
| 122 | { |
| 123 | public: |
| 124 | SPC7110Decomp(running_machine &machine, UINT32 size); |
| 125 | |
| 126 | running_machine &machine() const { return m_machine; } |
| 127 | |
| 128 | void init(running_machine &machine, UINT8 *ROM, UINT32 mode, UINT32 offset, UINT32 index); |
| 129 | void reset(); |
| 130 | |
| 131 | UINT8 read(UINT8 *ROM); |
| 132 | void write(UINT8 data); |
| 133 | void mode0(UINT8 init, UINT8 *ROM); |
| 134 | void mode1(UINT8 init, UINT8 *ROM); |
| 135 | void mode2(UINT8 init, UINT8 *ROM); |
| 136 | |
| 137 | UINT8 dataread(UINT8 *ROM); |
| 138 | UINT8 probability(UINT32 n); |
| 139 | UINT8 next_lps(UINT32 n); |
| 140 | UINT8 next_mps(UINT32 n); |
| 141 | UINT8 toggle_invert(UINT32 n); |
| 142 | UINT32 morton_2x8(UINT32 data); |
| 143 | UINT32 morton_4x8(UINT32 data); |
| 144 | |
| 145 | UINT32 m_decomp_mode; |
| 146 | UINT32 m_decomp_offset; |
| 147 | |
| 148 | UINT8 *m_decomp_buffer; |
| 149 | UINT32 m_decomp_buffer_rdoffset; |
| 150 | UINT32 m_decomp_buffer_wroffset; |
| 151 | UINT32 m_decomp_buffer_length; |
| 152 | |
| 153 | struct ContextState |
| 154 | { |
| 155 | UINT8 index; |
| 156 | UINT8 invert; |
| 157 | } m_context[32]; |
| 158 | |
| 159 | UINT32 m_morton16[2][256]; |
| 160 | UINT32 m_morton32[4][256]; |
| 161 | |
| 162 | |
| 163 | private: |
| 164 | running_machine& m_machine; |
| 165 | UINT32 m_rom_size; |
| 166 | }; |
| 167 | |
| 168 | SPC7110Decomp::SPC7110Decomp(running_machine &machine, UINT32 size) |
| 169 | : m_machine(machine), |
| 170 | m_rom_size(size) |
| 171 | { |
| 172 | m_decomp_buffer = (UINT8*)auto_alloc_array(machine, UINT8, SPC7110_DECOMP_BUFFER_SIZE); |
| 173 | reset(); |
| 174 | |
| 175 | for (int i = 0; i < 256; i++) |
| 176 | { |
| 177 | #define map(x, y) (((i >> x) & 1) << y) |
| 178 | //2x8-bit |
| 179 | m_morton16[1][i] = map(7, 15) + map(6, 7) + map(5, 14) + map(4, 6) |
| 180 | + map(3, 13) + map(2, 5) + map(1, 12) + map(0, 4); |
| 181 | m_morton16[0][i] = map(7, 11) + map(6, 3) + map(5, 10) + map(4, 2) |
| 182 | + map(3, 9) + map(2, 1) + map(1, 8) + map(0, 0); |
| 183 | //4x8-bit |
| 184 | m_morton32[3][i] = map(7, 31) + map(6, 23) + map(5, 15) + map(4, 7) |
| 185 | + map(3, 30) + map(2, 22) + map(1, 14) + map(0, 6); |
| 186 | m_morton32[2][i] = map(7, 29) + map(6, 21) + map(5, 13) + map(4, 5) |
| 187 | + map(3, 28) + map(2, 20) + map(1, 12) + map(0, 4); |
| 188 | m_morton32[1][i] = map(7, 27) + map(6, 19) + map(5, 11) + map(4, 3) |
| 189 | + map(3, 26) + map(2, 18) + map(1, 10) + map(0, 2); |
| 190 | m_morton32[0][i] = map(7, 25) + map(6, 17) + map(5, 9) + map(4, 1) |
| 191 | + map(3, 24) + map(2, 16) + map(1, 8) + map(0, 0); |
| 192 | #undef map |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | void SPC7110Decomp::reset() |
| 197 | { |
| 198 | //mode 3 is invalid; this is treated as a special case to always return 0x00 |
| 199 | //set to mode 3 so that reading decomp port before starting first decomp will return 0x00 |
| 200 | m_decomp_mode = 3; |
| 201 | |
| 202 | m_decomp_buffer_rdoffset = 0; |
| 203 | m_decomp_buffer_wroffset = 0; |
| 204 | m_decomp_buffer_length = 0; |
| 205 | } |
| 206 | |
| 207 | void SPC7110Decomp::init(running_machine &machine, UINT8 *ROM, UINT32 mode, UINT32 offset, UINT32 index) |
| 208 | { |
| 209 | m_decomp_mode = mode; |
| 210 | m_decomp_offset = offset; |
| 211 | |
| 212 | m_decomp_buffer_rdoffset = 0; |
| 213 | m_decomp_buffer_wroffset = 0; |
| 214 | m_decomp_buffer_length = 0; |
| 215 | |
| 216 | //reset context states |
| 217 | for (int i = 0; i < 32; i++) |
| 218 | { |
| 219 | m_context[i].index = 0; |
| 220 | m_context[i].invert = 0; |
| 221 | } |
| 222 | |
| 223 | switch (m_decomp_mode) |
| 224 | { |
| 225 | case 0: mode0(1, ROM); break; |
| 226 | case 1: mode1(1, ROM); break; |
| 227 | case 2: mode2(1, ROM); break; |
| 228 | } |
| 229 | |
| 230 | //decompress up to requested output data index |
| 231 | while (index--) |
| 232 | { |
| 233 | read(ROM); |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | UINT8 SPC7110Decomp::read(UINT8 *ROM) |
| 238 | { |
| 239 | UINT8 data; |
| 240 | |
| 241 | if (m_decomp_buffer_length == 0) |
| 242 | { |
| 243 | //decompress at least (SPC7110_DECOMP_BUFFER_SIZE / 2) bytes to the buffer |
| 244 | switch (m_decomp_mode) |
| 245 | { |
| 246 | case 0: |
| 247 | mode0(0, ROM); |
| 248 | break; |
| 249 | |
| 250 | case 1: |
| 251 | mode1(0, ROM); |
| 252 | break; |
| 253 | |
| 254 | case 2: |
| 255 | mode2(0, ROM); |
| 256 | break; |
| 257 | |
| 258 | default: |
| 259 | return 0x00; |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | data = m_decomp_buffer[m_decomp_buffer_rdoffset++]; |
| 264 | m_decomp_buffer_rdoffset &= SPC7110_DECOMP_BUFFER_SIZE - 1; |
| 265 | m_decomp_buffer_length--; |
| 266 | return data; |
| 267 | } |
| 268 | |
| 269 | void SPC7110Decomp::write(UINT8 data) |
| 270 | { |
| 271 | m_decomp_buffer[m_decomp_buffer_wroffset++] = data; |
| 272 | m_decomp_buffer_wroffset &= SPC7110_DECOMP_BUFFER_SIZE - 1; |
| 273 | m_decomp_buffer_length++; |
| 274 | } |
| 275 | |
| 276 | UINT8 SPC7110Decomp::dataread(UINT8 *ROM) |
| 277 | { |
| 278 | UINT32 size = m_rom_size - 0x100000; |
| 279 | while (m_decomp_offset >= size) |
| 280 | { |
| 281 | m_decomp_offset -= size; |
| 282 | } |
| 283 | return ROM[0x100000 + m_decomp_offset++]; |
| 284 | } |
| 285 | |
| 286 | void SPC7110Decomp::mode0(UINT8 init, UINT8 *ROM) |
| 287 | { |
| 288 | static UINT8 val, in, span; |
| 289 | static INT32 out, inverts, lps, in_count; |
| 290 | |
| 291 | if (init == 1) |
| 292 | { |
| 293 | out = inverts = lps = 0; |
| 294 | span = 0xff; |
| 295 | val = dataread(ROM); |
| 296 | in = dataread(ROM); |
| 297 | in_count = 8; |
| 298 | return; |
| 299 | } |
| 300 | |
| 301 | while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1)) |
| 302 | { |
| 303 | for (int bit = 0; bit < 8; bit++) |
| 304 | { |
| 305 | //get context |
| 306 | UINT8 mask = (1 << (bit & 3)) - 1; |
| 307 | UINT8 con = mask + ((inverts & mask) ^ (lps & mask)); |
| 308 | UINT32 prob, mps, flag_lps; |
| 309 | UINT32 shift = 0; |
| 310 | if (bit > 3) |
| 311 | { |
| 312 | con += 15; |
| 313 | } |
| 314 | |
| 315 | //get prob and mps |
| 316 | prob = probability(con); |
| 317 | mps = (((out >> 15) & 1) ^ m_context[con].invert); |
| 318 | |
| 319 | //get bit |
| 320 | if (val <= span - prob) //mps |
| 321 | { |
| 322 | span = span - prob; |
| 323 | out = (out << 1) + mps; |
| 324 | flag_lps = 0; |
| 325 | } |
| 326 | else //lps |
| 327 | { |
| 328 | val = val - (span - (prob - 1)); |
| 329 | span = prob - 1; |
| 330 | out = (out << 1) + 1 - mps; |
| 331 | flag_lps = 1; |
| 332 | } |
| 333 | |
| 334 | //renormalize |
| 335 | while (span < 0x7f) |
| 336 | { |
| 337 | shift++; |
| 338 | |
| 339 | span = (span << 1) + 1; |
| 340 | val = (val << 1) + (in >> 7); |
| 341 | |
| 342 | in <<= 1; |
| 343 | if (--in_count == 0) |
| 344 | { |
| 345 | in = dataread(ROM); |
| 346 | in_count = 8; |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | //update processing info |
| 351 | lps = (lps << 1) + flag_lps; |
| 352 | inverts = (inverts << 1) + m_context[con].invert; |
| 353 | |
| 354 | //update context state |
| 355 | if (flag_lps & toggle_invert(con)) |
| 356 | { |
| 357 | m_context[con].invert ^= 1; |
| 358 | } |
| 359 | if (flag_lps) |
| 360 | { |
| 361 | m_context[con].index = next_lps(con); |
| 362 | } |
| 363 | else if (shift) |
| 364 | { |
| 365 | m_context[con].index = next_mps(con); |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | //save byte |
| 370 | write(out); |
| 371 | } |
| 372 | } |
| 373 | |
| 374 | void SPC7110Decomp::mode1(UINT8 init, UINT8 *ROM) |
| 375 | { |
| 376 | static INT32 pixelorder[4], realorder[4]; |
| 377 | static UINT8 in, val, span; |
| 378 | static INT32 out, inverts, lps, in_count; |
| 379 | |
| 380 | if (init == 1) |
| 381 | { |
| 382 | for (int i = 0; i < 4; i++) |
| 383 | { |
| 384 | pixelorder[i] = i; |
| 385 | } |
| 386 | out = inverts = lps = 0; |
| 387 | span = 0xff; |
| 388 | val = dataread(ROM); |
| 389 | in = dataread(ROM); |
| 390 | in_count = 8; |
| 391 | return; |
| 392 | } |
| 393 | |
| 394 | while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1)) |
| 395 | { |
| 396 | UINT16 data; |
| 397 | for (int pixel = 0; pixel < 8; pixel++) |
| 398 | { |
| 399 | //get first symbol context |
| 400 | UINT32 a = ((out >> (1 * 2)) & 3); |
| 401 | UINT32 b = ((out >> (7 * 2)) & 3); |
| 402 | UINT32 c = ((out >> (8 * 2)) & 3); |
| 403 | UINT32 con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); |
| 404 | |
| 405 | //update pixel order |
| 406 | UINT32 m, n; |
| 407 | for (m = 0; m < 4; m++) |
| 408 | { |
| 409 | if (pixelorder[m] == a) |
| 410 | { |
| 411 | break; |
| 412 | } |
| 413 | } |
| 414 | for (n = m; n > 0; n--) |
| 415 | { |
| 416 | pixelorder[n] = pixelorder[n - 1]; |
| 417 | } |
| 418 | pixelorder[0] = a; |
| 419 | |
| 420 | //calculate the real pixel order |
| 421 | for (m = 0; m < 4; m++) |
| 422 | { |
| 423 | realorder[m] = pixelorder[m]; |
| 424 | } |
| 425 | |
| 426 | //rotate reference pixel c value to top |
| 427 | for (m = 0; m < 4; m++) |
| 428 | { |
| 429 | if (realorder[m] == c) |
| 430 | { |
| 431 | break; |
| 432 | } |
| 433 | } |
| 434 | for (n = m; n > 0; n--) |
| 435 | { |
| 436 | realorder[n] = realorder[n - 1]; |
| 437 | } |
| 438 | realorder[0] = c; |
| 439 | |
| 440 | //rotate reference pixel b value to top |
| 441 | for (m = 0; m < 4; m++) |
| 442 | { |
| 443 | if (realorder[m] == b) |
| 444 | { |
| 445 | break; |
| 446 | } |
| 447 | } |
| 448 | for (n = m; n > 0; n--) |
| 449 | { |
| 450 | realorder[n] = realorder[n - 1]; |
| 451 | } |
| 452 | realorder[0] = b; |
| 453 | |
| 454 | //rotate reference pixel a value to top |
| 455 | for (m = 0; m < 4; m++) |
| 456 | { |
| 457 | if (realorder[m] == a) |
| 458 | { |
| 459 | break; |
| 460 | } |
| 461 | } |
| 462 | for (n = m; n > 0; n--) |
| 463 | { |
| 464 | realorder[n] = realorder[n - 1]; |
| 465 | } |
| 466 | realorder[0] = a; |
| 467 | |
| 468 | //get 2 symbols |
| 469 | for (int bit = 0; bit < 2; bit++) |
| 470 | { |
| 471 | //get prob |
| 472 | UINT32 prob = probability(con); |
| 473 | UINT32 shift = 0; |
| 474 | |
| 475 | //get symbol |
| 476 | UINT32 flag_lps; |
| 477 | if (val <= span - prob) //mps |
| 478 | { |
| 479 | span = span - prob; |
| 480 | flag_lps = 0; |
| 481 | } |
| 482 | else //lps |
| 483 | { |
| 484 | val = val - (span - (prob - 1)); |
| 485 | span = prob - 1; |
| 486 | flag_lps = 1; |
| 487 | } |
| 488 | |
| 489 | //renormalize |
| 490 | while (span < 0x7f) |
| 491 | { |
| 492 | shift++; |
| 493 | |
| 494 | span = (span << 1) + 1; |
| 495 | val = (val << 1) + (in >> 7); |
| 496 | |
| 497 | in <<= 1; |
| 498 | if (--in_count == 0) |
| 499 | { |
| 500 | in = dataread(ROM); |
| 501 | in_count = 8; |
| 502 | } |
| 503 | } |
| 504 | |
| 505 | //update processing info |
| 506 | lps = (lps << 1) + flag_lps; |
| 507 | inverts = (inverts << 1) + m_context[con].invert; |
| 508 | |
| 509 | //update context state |
| 510 | if (flag_lps & toggle_invert(con)) |
| 511 | { |
| 512 | m_context[con].invert ^= 1; |
| 513 | } |
| 514 | if (flag_lps) |
| 515 | { |
| 516 | m_context[con].index = next_lps(con); |
| 517 | } |
| 518 | else if (shift) |
| 519 | { |
| 520 | m_context[con].index = next_mps(con); |
| 521 | } |
| 522 | |
| 523 | //get next context |
| 524 | con = 5 + (con << 1) + ((lps ^ inverts) & 1); |
| 525 | } |
| 526 | |
| 527 | //get pixel |
| 528 | b = realorder[(lps ^ inverts) & 3]; |
| 529 | out = (out << 2) + b; |
| 530 | } |
| 531 | |
| 532 | //turn pixel data into bitplanes |
| 533 | data = morton_2x8(out); |
| 534 | write(data >> 8); |
| 535 | write(data >> 0); |
| 536 | } |
| 537 | } |
| 538 | |
| 539 | void SPC7110Decomp::mode2(UINT8 init, UINT8 *ROM) |
| 540 | { |
| 541 | static INT32 pixelorder[16], realorder[16]; |
| 542 | static UINT8 bitplanebuffer[16], buffer_index; |
| 543 | static UINT8 in, val, span; |
| 544 | static INT32 out0, out1, inverts, lps, in_count; |
| 545 | |
| 546 | if (init == 1) |
| 547 | { |
| 548 | for (int i = 0; i < 16; i++) |
| 549 | { |
| 550 | pixelorder[i] = i; |
| 551 | } |
| 552 | buffer_index = 0; |
| 553 | out0 = out1 = inverts = lps = 0; |
| 554 | span = 0xff; |
| 555 | val = dataread(ROM); |
| 556 | in = dataread(ROM); |
| 557 | in_count = 8; |
| 558 | return; |
| 559 | } |
| 560 | |
| 561 | while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1)) |
| 562 | { |
| 563 | UINT32 data; |
| 564 | for (int pixel = 0; pixel < 8; pixel++) |
| 565 | { |
| 566 | //get first symbol context |
| 567 | UINT32 a = ((out0 >> (0 * 4)) & 15); |
| 568 | UINT32 b = ((out0 >> (7 * 4)) & 15); |
| 569 | UINT32 c = ((out1 >> (0 * 4)) & 15); |
| 570 | UINT32 con = 0; |
| 571 | UINT32 refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); |
| 572 | |
| 573 | //update pixel order |
| 574 | UINT32 m, n; |
| 575 | for (m = 0; m < 16; m++) |
| 576 | { |
| 577 | if (pixelorder[m] == a) |
| 578 | { |
| 579 | break; |
| 580 | } |
| 581 | } |
| 582 | for (n = m; n > 0; n--) |
| 583 | { |
| 584 | pixelorder[n] = pixelorder[n - 1]; |
| 585 | } |
| 586 | pixelorder[0] = a; |
| 587 | |
| 588 | //calculate the real pixel order |
| 589 | for (m = 0; m < 16; m++) |
| 590 | { |
| 591 | realorder[m] = pixelorder[m]; |
| 592 | } |
| 593 | |
| 594 | //rotate reference pixel c value to top |
| 595 | for (m = 0; m < 16; m++) |
| 596 | { |
| 597 | if (realorder[m] == c) |
| 598 | { |
| 599 | break; |
| 600 | } |
| 601 | } |
| 602 | for (n = m; n > 0; n--) |
| 603 | { |
| 604 | realorder[n] = realorder[n - 1]; |
| 605 | } |
| 606 | realorder[0] = c; |
| 607 | |
| 608 | //rotate reference pixel b value to top |
| 609 | for (m = 0; m < 16; m++) |
| 610 | { |
| 611 | if (realorder[m] == b) |
| 612 | { |
| 613 | break; |
| 614 | } |
| 615 | } |
| 616 | for (n = m; n > 0; n--) |
| 617 | { |
| 618 | realorder[n] = realorder[n - 1]; |
| 619 | } |
| 620 | realorder[0] = b; |
| 621 | |
| 622 | //rotate reference pixel a value to top |
| 623 | for (m = 0; m < 16; m++) |
| 624 | { |
| 625 | if (realorder[m] == a) |
| 626 | { |
| 627 | break; |
| 628 | } |
| 629 | } |
| 630 | for (n = m; n > 0; n--) |
| 631 | { |
| 632 | realorder[n] = realorder[n - 1]; |
| 633 | } |
| 634 | realorder[0] = a; |
| 635 | |
| 636 | //get 4 symbols |
| 637 | for (int bit = 0; bit < 4; bit++) |
| 638 | { |
| 639 | UINT32 invertbit, shift; |
| 640 | |
| 641 | //get prob |
| 642 | UINT32 prob = probability(con); |
| 643 | |
| 644 | //get symbol |
| 645 | UINT32 flag_lps; |
| 646 | if (val <= span - prob) //mps |
| 647 | { |
| 648 | span = span - prob; |
| 649 | flag_lps = 0; |
| 650 | } |
| 651 | else //lps |
| 652 | { |
| 653 | val = val - (span - (prob - 1)); |
| 654 | span = prob - 1; |
| 655 | flag_lps = 1; |
| 656 | } |
| 657 | |
| 658 | //renormalize |
| 659 | shift = 0; |
| 660 | while (span < 0x7f) |
| 661 | { |
| 662 | shift++; |
| 663 | |
| 664 | span = (span << 1) + 1; |
| 665 | val = (val << 1) + (in >> 7); |
| 666 | |
| 667 | in <<= 1; |
| 668 | if (--in_count == 0) |
| 669 | { |
| 670 | in = dataread(ROM); |
| 671 | in_count = 8; |
| 672 | } |
| 673 | } |
| 674 | |
| 675 | //update processing info |
| 676 | lps = (lps << 1) + flag_lps; |
| 677 | invertbit = m_context[con].invert; |
| 678 | inverts = (inverts << 1) + invertbit; |
| 679 | |
| 680 | //update context state |
| 681 | if (flag_lps & toggle_invert(con)) |
| 682 | { |
| 683 | m_context[con].invert ^= 1; |
| 684 | } |
| 685 | if (flag_lps) |
| 686 | { |
| 687 | m_context[con].index = next_lps(con); |
| 688 | } |
| 689 | else if (shift) |
| 690 | { |
| 691 | m_context[con].index = next_mps(con); |
| 692 | } |
| 693 | |
| 694 | //get next context |
| 695 | con = spc7110_mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0); |
| 696 | } |
| 697 | |
| 698 | //get pixel |
| 699 | b = realorder[(lps ^ inverts) & 0x0f]; |
| 700 | out1 = (out1 << 4) + ((out0 >> 28) & 0x0f); |
| 701 | out0 = (out0 << 4) + b; |
| 702 | } |
| 703 | |
| 704 | //convert pixel data into bitplanes |
| 705 | data = morton_4x8(out0); |
| 706 | write(data >> 24); |
| 707 | write(data >> 16); |
| 708 | bitplanebuffer[buffer_index++] = data >> 8; |
| 709 | bitplanebuffer[buffer_index++] = data >> 0; |
| 710 | |
| 711 | if (buffer_index == 16) |
| 712 | { |
| 713 | for (int i = 0; i < 16; i++) |
| 714 | { |
| 715 | write(bitplanebuffer[i]); |
| 716 | } |
| 717 | buffer_index = 0; |
| 718 | } |
| 719 | } |
| 720 | } |
| 721 | |
| 722 | UINT8 SPC7110Decomp::probability(UINT32 n) |
| 723 | { |
| 724 | return spc7110_evolution_table[m_context[n].index][0]; |
| 725 | } |
| 726 | |
| 727 | UINT8 SPC7110Decomp::next_lps(UINT32 n) |
| 728 | { |
| 729 | return spc7110_evolution_table[m_context[n].index][1]; |
| 730 | } |
| 731 | |
| 732 | UINT8 SPC7110Decomp::next_mps(UINT32 n) |
| 733 | { |
| 734 | return spc7110_evolution_table[m_context[n].index][2]; |
| 735 | } |
| 736 | |
| 737 | UINT8 SPC7110Decomp::toggle_invert(UINT32 n) |
| 738 | { |
| 739 | return spc7110_evolution_table[m_context[n].index][3]; |
| 740 | } |
| 741 | |
| 742 | UINT32 SPC7110Decomp::morton_2x8(UINT32 data) |
| 743 | { |
| 744 | //reverse morton lookup: de-interleave two 8-bit values |
| 745 | //15, 13, 11, 9, 7, 5, 3, 1 -> 15- 8 |
| 746 | //14, 12, 10, 8, 6, 4, 2, 0 -> 7- 0 |
| 747 | return m_morton16[0][(data >> 0) & 255] + m_morton16[1][(data >> 8) & 255]; |
| 748 | } |
| 749 | |
| 750 | UINT32 SPC7110Decomp::morton_4x8(UINT32 data) |
| 751 | { |
| 752 | //reverse morton lookup: de-interleave four 8-bit values |
| 753 | //31, 27, 23, 19, 15, 11, 7, 3 -> 31-24 |
| 754 | //30, 26, 22, 18, 14, 10, 6, 2 -> 23-16 |
| 755 | //29, 25, 21, 17, 13, 9, 5, 1 -> 15- 8 |
| 756 | //28, 24, 20, 16, 12, 8, 4, 0 -> 7- 0 |
| 757 | return m_morton32[0][(data >> 0) & 255] + m_morton32[1][(data >> 8) & 255] |
| 758 | + m_morton32[2][(data >> 16) & 255] + m_morton32[3][(data >> 24) & 255]; |
| 759 | } |
| 760 | |
| 761 | static void spc7110_update_time(running_machine &machine, UINT8 offset); |
| 762 | |
| 763 | enum RTC_State |
| 764 | { |
| 765 | RTCS_Inactive, |
| 766 | RTCS_ModeSelect, |
| 767 | RTCS_IndexSelect, |
| 768 | RTCS_Write |
| 769 | }; |
| 770 | |
| 771 | enum RTC_Mode |
| 772 | { |
| 773 | RTCM_Linear = 0x03, |
| 774 | RTCM_Indexed = 0x0c |
| 775 | }; |
| 776 | |
| 777 | static const UINT32 spc7110_months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
| 778 | |
| 779 | struct snes_spc7110_t |
| 780 | { |
| 781 | //================== |
| 782 | //decompression unit |
| 783 | //================== |
| 784 | UINT8 r4801; // compression table low |
| 785 | UINT8 r4802; // compression table high |
| 786 | UINT8 r4803; // compression table bank |
| 787 | UINT8 r4804; // compression table index |
| 788 | UINT8 r4805; // decompression buffer index low |
| 789 | UINT8 r4806; // decompression buffer index high |
| 790 | UINT8 r4807; // ??? |
| 791 | UINT8 r4808; // ??? |
| 792 | UINT8 r4809; // compression length low |
| 793 | UINT8 r480a; // compression length high |
| 794 | UINT8 r480b; // decompression control register |
| 795 | UINT8 r480c; // decompression status |
| 796 | |
| 797 | SPC7110Decomp* decomp; |
| 798 | |
| 799 | UINT8 r4811; // data pointer low |
| 800 | UINT8 r4812; // data pointer high |
| 801 | UINT8 r4813; // data pointer bank |
| 802 | UINT8 r4814; // data adjust low |
| 803 | UINT8 r4815; // data adjust high |
| 804 | UINT8 r4816; // data increment low |
| 805 | UINT8 r4817; // data increment high |
| 806 | UINT8 r4818; // data port control register |
| 807 | |
| 808 | UINT8 r481x; |
| 809 | |
| 810 | UINT8 r4814_latch; |
| 811 | UINT8 r4815_latch; |
| 812 | |
| 813 | //========= |
| 814 | //math unit |
| 815 | //========= |
| 816 | UINT8 r4820; // 16-bit multiplicand B0, 32-bit dividend B0 |
| 817 | UINT8 r4821; // 16-bit multiplicand B1, 32-bit dividend B1 |
| 818 | UINT8 r4822; // 32-bit dividend B2 |
| 819 | UINT8 r4823; // 32-bit dividend B3 |
| 820 | UINT8 r4824; // 16-bit multiplier B0 |
| 821 | UINT8 r4825; // 16-bit multiplier B1 |
| 822 | UINT8 r4826; // 16-bit divisor B0 |
| 823 | UINT8 r4827; // 16-bit divisor B1 |
| 824 | UINT8 r4828; // 32-bit product B0, 32-bit quotient B0 |
| 825 | UINT8 r4829; // 32-bit product B1, 32-bit quotient B1 |
| 826 | UINT8 r482a; // 32-bit product B2, 32-bit quotient B2 |
| 827 | UINT8 r482b; // 32-bit product B3, 32-bit quotient B3 |
| 828 | UINT8 r482c; // 16-bit remainder B0 |
| 829 | UINT8 r482d; // 16-bit remainder B1 |
| 830 | UINT8 r482e; // math control register |
| 831 | UINT8 r482f; // math status |
| 832 | |
| 833 | //=================== |
| 834 | //memory mapping unit |
| 835 | //=================== |
| 836 | UINT8 r4830; // SRAM write enable |
| 837 | UINT8 r4831; // $[d0-df]:[0000-ffff] mapping |
| 838 | UINT8 r4832; // $[e0-ef]:[0000-ffff] mapping |
| 839 | UINT8 r4833; // $[f0-ff]:[0000-ffff] mapping |
| 840 | UINT8 r4834; // ??? |
| 841 | |
| 842 | UINT32 dx_offset; |
| 843 | UINT32 ex_offset; |
| 844 | UINT32 fx_offset; |
| 845 | |
| 846 | //==================== |
| 847 | //real-time clock unit |
| 848 | //==================== |
| 849 | UINT8 r4840; // RTC latch |
| 850 | UINT8 r4841; // RTC index/data port |
| 851 | UINT8 r4842; // RTC status |
| 852 | |
| 853 | UINT32 rtc_state; |
| 854 | UINT32 rtc_mode; |
| 855 | UINT32 rtc_index; |
| 856 | |
| 857 | UINT64 rtc_offset; |
| 858 | |
| 859 | UINT8 rtc_ram[16]; // 0-12 secs, min, hrs, etc.; 13-14-15 control registers |
| 860 | |
| 861 | UINT32 size; |
| 862 | }; |
| 863 | |
| 864 | static snes_spc7110_t snes_spc7110; |
| 865 | |
| 866 | void spc7110_init(running_machine& machine) |
| 867 | { |
| 868 | snes_state *state = machine.driver_data<snes_state>(); |
| 869 | |
| 870 | snes_spc7110.r4801 = 0x00; |
| 871 | snes_spc7110.r4802 = 0x00; |
| 872 | snes_spc7110.r4803 = 0x00; |
| 873 | snes_spc7110.r4804 = 0x00; |
| 874 | snes_spc7110.r4805 = 0x00; |
| 875 | snes_spc7110.r4806 = 0x00; |
| 876 | snes_spc7110.r4807 = 0x00; |
| 877 | snes_spc7110.r4808 = 0x00; |
| 878 | snes_spc7110.r4809 = 0x00; |
| 879 | snes_spc7110.r480a = 0x00; |
| 880 | snes_spc7110.r480b = 0x00; |
| 881 | snes_spc7110.r480c = 0x00; |
| 882 | |
| 883 | snes_spc7110.r4811 = 0x00; |
| 884 | snes_spc7110.r4812 = 0x00; |
| 885 | snes_spc7110.r4813 = 0x00; |
| 886 | snes_spc7110.r4814 = 0x00; |
| 887 | snes_spc7110.r4815 = 0x00; |
| 888 | snes_spc7110.r4816 = 0x00; |
| 889 | snes_spc7110.r4817 = 0x00; |
| 890 | snes_spc7110.r4818 = 0x00; |
| 891 | |
| 892 | snes_spc7110.r481x = 0x00; |
| 893 | snes_spc7110.r4814_latch = 0; |
| 894 | snes_spc7110.r4815_latch = 0; |
| 895 | |
| 896 | snes_spc7110.r4820 = 0x00; |
| 897 | snes_spc7110.r4821 = 0x00; |
| 898 | snes_spc7110.r4822 = 0x00; |
| 899 | snes_spc7110.r4823 = 0x00; |
| 900 | snes_spc7110.r4824 = 0x00; |
| 901 | snes_spc7110.r4825 = 0x00; |
| 902 | snes_spc7110.r4826 = 0x00; |
| 903 | snes_spc7110.r4827 = 0x00; |
| 904 | snes_spc7110.r4828 = 0x00; |
| 905 | snes_spc7110.r4829 = 0x00; |
| 906 | snes_spc7110.r482a = 0x00; |
| 907 | snes_spc7110.r482b = 0x00; |
| 908 | snes_spc7110.r482c = 0x00; |
| 909 | snes_spc7110.r482d = 0x00; |
| 910 | snes_spc7110.r482e = 0x00; |
| 911 | snes_spc7110.r482f = 0x00; |
| 912 | |
| 913 | snes_spc7110.r4830 = 0x00; |
| 914 | spc7110_mmio_write(machine, 0x4831, 0); |
| 915 | spc7110_mmio_write(machine, 0x4832, 1); |
| 916 | spc7110_mmio_write(machine, 0x4833, 2); |
| 917 | snes_spc7110.r4834 = 0x00; |
| 918 | |
| 919 | snes_spc7110.r4840 = 0x00; |
| 920 | snes_spc7110.r4841 = 0x00; |
| 921 | snes_spc7110.r4842 = 0x00; |
| 922 | |
| 923 | snes_spc7110.size = state->m_cart_size; |
| 924 | |
| 925 | snes_spc7110.decomp = auto_alloc(machine, SPC7110Decomp(machine, snes_spc7110.size)); |
| 926 | } |
| 927 | |
| 928 | void spc7110rtc_init(running_machine& machine) |
| 929 | { |
| 930 | spc7110_init(machine); |
| 931 | |
| 932 | snes_spc7110.rtc_state = RTCS_Inactive; |
| 933 | snes_spc7110.rtc_mode = RTCM_Linear; |
| 934 | snes_spc7110.rtc_index = 0; |
| 935 | |
| 936 | snes_spc7110.rtc_offset = 0; |
| 937 | |
| 938 | spc7110_update_time(machine, 0); |
| 939 | } |
| 940 | |
| 941 | static UINT32 spc7110_datarom_addr(UINT32 addr) |
| 942 | { |
| 943 | UINT32 size = snes_spc7110.size - 0x100000; |
| 944 | while (addr >= size) |
| 945 | { |
| 946 | addr -= size; |
| 947 | } |
| 948 | return addr + 0x100000; |
| 949 | } |
| 950 | |
| 951 | static UINT32 spc7110_data_pointer(void) |
| 952 | { |
| 953 | return snes_spc7110.r4811 + (snes_spc7110.r4812 << 8) + (snes_spc7110.r4813 << 16); |
| 954 | } |
| 955 | |
| 956 | static UINT32 spc7110_data_adjust(void) |
| 957 | { |
| 958 | return snes_spc7110.r4814 + (snes_spc7110.r4815 << 8); |
| 959 | } |
| 960 | |
| 961 | static UINT32 spc7110_data_increment(void) |
| 962 | { |
| 963 | return snes_spc7110.r4816 + (snes_spc7110.r4817 << 8); |
| 964 | } |
| 965 | |
| 966 | static void spc7110_set_data_pointer(UINT32 addr) |
| 967 | { |
| 968 | snes_spc7110.r4811 = addr; |
| 969 | snes_spc7110.r4812 = addr >> 8; |
| 970 | snes_spc7110.r4813 = addr >> 16; |
| 971 | } |
| 972 | |
| 973 | static void spc7110_set_data_adjust(UINT32 addr) |
| 974 | { |
| 975 | snes_spc7110.r4814 = addr; |
| 976 | snes_spc7110.r4815 = addr >> 8; |
| 977 | } |
| 978 | |
| 979 | // FIXME: SPC7110 RTC is capable of rounding/adding/zero-ing seconds, so |
| 980 | // we should probably keep track internally of the time rather than updating |
| 981 | // to the system time at each call with a "offset" tracking as we do now... |
| 982 | // (and indeed current code fails to pass Tengai Makyou Zero tests) |
| 983 | static void spc7110_update_time(running_machine &machine, UINT8 offset) |
| 984 | { |
| 985 | system_time curtime, *systime = &curtime; |
| 986 | machine.current_datetime(curtime); |
| 987 | int update = 1; |
| 988 | |
| 989 | snes_spc7110.rtc_offset += offset; |
| 990 | |
| 991 | // TEST: can we go beyond 24hrs of rounding?!? I doubt it will ever go beyond 3600, but I could be wrong... |
| 992 | assert(snes_spc7110.rtc_offset < 86400); |
| 993 | |
| 994 | /* do not update if CR0 or CR2 timer disable flags are set */ |
| 995 | if ((snes_spc7110.rtc_ram[13] & 0x01) || (snes_spc7110.rtc_ram[15] & 0x03)) |
| 996 | update = 0; |
| 997 | |
| 998 | if (update) |
| 999 | { |
| 1000 | /* update time with offset, assuming offset < 3600s */ |
| 1001 | UINT8 second = systime->local_time.second; |
| 1002 | UINT8 minute = systime->local_time.minute; |
| 1003 | UINT8 hour = systime->local_time.hour; |
| 1004 | UINT8 mday = systime->local_time.mday; |
| 1005 | |
| 1006 | while (snes_spc7110.rtc_offset >= 3600) |
| 1007 | { |
| 1008 | snes_spc7110.rtc_offset -= 3600; |
| 1009 | hour++; |
| 1010 | |
| 1011 | if (hour == 24) |
| 1012 | { |
| 1013 | mday++; |
| 1014 | hour = 0; |
| 1015 | } |
| 1016 | } |
| 1017 | |
| 1018 | while (snes_spc7110.rtc_offset >= 60) |
| 1019 | { |
| 1020 | snes_spc7110.rtc_offset -= 60; |
| 1021 | minute++; |
| 1022 | |
| 1023 | if (minute == 60) |
| 1024 | { |
| 1025 | hour++; |
| 1026 | minute = 0; |
| 1027 | } |
| 1028 | } |
| 1029 | |
| 1030 | while (snes_spc7110.rtc_offset) |
| 1031 | { |
| 1032 | snes_spc7110.rtc_offset -= 1; |
| 1033 | second++; |
| 1034 | |
| 1035 | if (second == 60) |
| 1036 | { |
| 1037 | minute++; |
| 1038 | second = 0; |
| 1039 | } |
| 1040 | } |
| 1041 | |
| 1042 | snes_spc7110.rtc_ram[0] = second % 10; |
| 1043 | snes_spc7110.rtc_ram[1] = second / 10; |
| 1044 | snes_spc7110.rtc_ram[2] = minute % 10; |
| 1045 | snes_spc7110.rtc_ram[3] = minute / 10; |
| 1046 | snes_spc7110.rtc_ram[4] = hour % 10; |
| 1047 | snes_spc7110.rtc_ram[5] = hour / 10; |
| 1048 | snes_spc7110.rtc_ram[6] = mday % 10; |
| 1049 | snes_spc7110.rtc_ram[7] = mday / 10; |
| 1050 | snes_spc7110.rtc_ram[8] = systime->local_time.month % 10; |
| 1051 | snes_spc7110.rtc_ram[9] = systime->local_time.month / 10; |
| 1052 | snes_spc7110.rtc_ram[8] = systime->local_time.month; |
| 1053 | snes_spc7110.rtc_ram[10] = (systime->local_time.year - 1900) % 10; |
| 1054 | snes_spc7110.rtc_ram[11] = ((systime->local_time.year - 1900) / 10) % 10; |
| 1055 | snes_spc7110.rtc_ram[12] = systime->local_time.weekday % 7; |
| 1056 | } |
| 1057 | } |
| 1058 | |
| 1059 | UINT8 spc7110_mmio_read(address_space &space, UINT32 addr) |
| 1060 | { |
| 1061 | running_machine &machine = space.machine(); |
| 1062 | UINT8 *ROM = machine.root_device().memregion("cart")->base(); |
| 1063 | |
| 1064 | addr &= 0xffff; |
| 1065 | |
| 1066 | switch(addr) |
| 1067 | { |
| 1068 | //================== |
| 1069 | //decompression unit |
| 1070 | //================== |
| 1071 | |
| 1072 | case 0x4800: |
| 1073 | { |
| 1074 | UINT16 counter = (snes_spc7110.r4809 + (snes_spc7110.r480a << 8)); |
| 1075 | counter--; |
| 1076 | snes_spc7110.r4809 = counter; |
| 1077 | snes_spc7110.r480a = counter >> 8; |
| 1078 | return snes_spc7110.decomp->read(ROM); |
| 1079 | } |
| 1080 | case 0x4801: return snes_spc7110.r4801; |
| 1081 | case 0x4802: return snes_spc7110.r4802; |
| 1082 | case 0x4803: return snes_spc7110.r4803; |
| 1083 | case 0x4804: return snes_spc7110.r4804; |
| 1084 | case 0x4805: return snes_spc7110.r4805; |
| 1085 | case 0x4806: return snes_spc7110.r4806; |
| 1086 | case 0x4807: return snes_spc7110.r4807; |
| 1087 | case 0x4808: return snes_spc7110.r4808; |
| 1088 | case 0x4809: return snes_spc7110.r4809; |
| 1089 | case 0x480a: return snes_spc7110.r480a; |
| 1090 | case 0x480b: return snes_spc7110.r480b; |
| 1091 | case 0x480c: |
| 1092 | { |
| 1093 | UINT8 status = snes_spc7110.r480c; |
| 1094 | snes_spc7110.r480c &= 0x7f; |
| 1095 | return status; |
| 1096 | } |
| 1097 | |
| 1098 | //============== |
| 1099 | //data port unit |
| 1100 | //============== |
| 1101 | |
| 1102 | case 0x4810: |
| 1103 | { |
| 1104 | UINT8 data; |
| 1105 | UINT32 address, adjust, adjustaddr; |
| 1106 | |
| 1107 | if (snes_spc7110.r481x != 0x07) return 0x00; |
| 1108 | |
| 1109 | address = spc7110_data_pointer(); |
| 1110 | adjust = spc7110_data_adjust(); |
| 1111 | if (snes_spc7110.r4818 & 8) |
| 1112 | { |
| 1113 | adjust = (INT16)adjust; //16-bit sign extend |
| 1114 | } |
| 1115 | |
| 1116 | adjustaddr = address; |
| 1117 | if (snes_spc7110.r4818 & 2) |
| 1118 | { |
| 1119 | adjustaddr += adjust; |
| 1120 | spc7110_set_data_adjust(adjust + 1); |
| 1121 | } |
| 1122 | |
| 1123 | data = ROM[spc7110_datarom_addr(adjustaddr)]; |
| 1124 | if (!(snes_spc7110.r4818 & 2)) |
| 1125 | { |
| 1126 | UINT32 increment = (snes_spc7110.r4818 & 1) ? spc7110_data_increment() : 1; |
| 1127 | if (snes_spc7110.r4818 & 4) |
| 1128 | { |
| 1129 | increment = (INT16)increment; //16-bit sign extend |
| 1130 | } |
| 1131 | |
| 1132 | if ((snes_spc7110.r4818 & 16) == 0) |
| 1133 | { |
| 1134 | spc7110_set_data_pointer(address + increment); |
| 1135 | } |
| 1136 | else |
| 1137 | { |
| 1138 | spc7110_set_data_adjust(adjust + increment); |
| 1139 | } |
| 1140 | } |
| 1141 | |
| 1142 | return data; |
| 1143 | } |
| 1144 | case 0x4811: return snes_spc7110.r4811; |
| 1145 | case 0x4812: return snes_spc7110.r4812; |
| 1146 | case 0x4813: return snes_spc7110.r4813; |
| 1147 | case 0x4814: return snes_spc7110.r4814; |
| 1148 | case 0x4815: return snes_spc7110.r4815; |
| 1149 | case 0x4816: return snes_spc7110.r4816; |
| 1150 | case 0x4817: return snes_spc7110.r4817; |
| 1151 | case 0x4818: return snes_spc7110.r4818; |
| 1152 | case 0x481a: |
| 1153 | { |
| 1154 | UINT8 data; |
| 1155 | UINT32 address, adjust; |
| 1156 | if (snes_spc7110.r481x != 0x07) |
| 1157 | { |
| 1158 | return 0x00; |
| 1159 | } |
| 1160 | |
| 1161 | address = spc7110_data_pointer(); |
| 1162 | adjust = spc7110_data_adjust(); |
| 1163 | if (snes_spc7110.r4818 & 8) |
| 1164 | { |
| 1165 | adjust = (INT16)adjust; //16-bit sign extend |
| 1166 | } |
| 1167 | |
| 1168 | data = ROM[spc7110_datarom_addr(address + adjust)]; |
| 1169 | if ((snes_spc7110.r4818 & 0x60) == 0x60) |
| 1170 | { |
| 1171 | if ((snes_spc7110.r4818 & 16) == 0) |
| 1172 | { |
| 1173 | spc7110_set_data_pointer(address + adjust); |
| 1174 | } |
| 1175 | else |
| 1176 | { |
| 1177 | spc7110_set_data_adjust(adjust + adjust); |
| 1178 | } |
| 1179 | } |
| 1180 | |
| 1181 | return data; |
| 1182 | } |
| 1183 | |
| 1184 | //========= |
| 1185 | //math unit |
| 1186 | //========= |
| 1187 | |
| 1188 | case 0x4820: return snes_spc7110.r4820; |
| 1189 | case 0x4821: return snes_spc7110.r4821; |
| 1190 | case 0x4822: return snes_spc7110.r4822; |
| 1191 | case 0x4823: return snes_spc7110.r4823; |
| 1192 | case 0x4824: return snes_spc7110.r4824; |
| 1193 | case 0x4825: return snes_spc7110.r4825; |
| 1194 | case 0x4826: return snes_spc7110.r4826; |
| 1195 | case 0x4827: return snes_spc7110.r4827; |
| 1196 | case 0x4828: return snes_spc7110.r4828; |
| 1197 | case 0x4829: return snes_spc7110.r4829; |
| 1198 | case 0x482a: return snes_spc7110.r482a; |
| 1199 | case 0x482b: return snes_spc7110.r482b; |
| 1200 | case 0x482c: return snes_spc7110.r482c; |
| 1201 | case 0x482d: return snes_spc7110.r482d; |
| 1202 | case 0x482e: return snes_spc7110.r482e; |
| 1203 | case 0x482f: |
| 1204 | { |
| 1205 | UINT8 status = snes_spc7110.r482f; |
| 1206 | snes_spc7110.r482f &= 0x7f; |
| 1207 | return status; |
| 1208 | } |
| 1209 | |
| 1210 | //=================== |
| 1211 | //memory mapping unit |
| 1212 | //=================== |
| 1213 | |
| 1214 | case 0x4830: return snes_spc7110.r4830; |
| 1215 | case 0x4831: return snes_spc7110.r4831; |
| 1216 | case 0x4832: return snes_spc7110.r4832; |
| 1217 | case 0x4833: return snes_spc7110.r4833; |
| 1218 | case 0x4834: return snes_spc7110.r4834; |
| 1219 | |
| 1220 | //==================== |
| 1221 | //real-time clock unit |
| 1222 | //==================== |
| 1223 | case 0x4840: return snes_spc7110.r4840; |
| 1224 | case 0x4841: |
| 1225 | { |
| 1226 | UINT8 data = 0; |
| 1227 | if (snes_spc7110.rtc_state == RTCS_Inactive || snes_spc7110.rtc_state == RTCS_ModeSelect) |
| 1228 | return 0x00; |
| 1229 | |
| 1230 | snes_spc7110.r4842 = 0x80; |
| 1231 | data = snes_spc7110.rtc_ram[snes_spc7110.rtc_index]; |
| 1232 | snes_spc7110.rtc_index = (snes_spc7110.rtc_index + 1) & 15; |
| 1233 | return data; |
| 1234 | } |
| 1235 | case 0x4842: |
| 1236 | { |
| 1237 | UINT8 status = snes_spc7110.r4842; |
| 1238 | snes_spc7110.r4842 &= 0x7f; |
| 1239 | return status; |
| 1240 | } |
| 1241 | } |
| 1242 | |
| 1243 | return snes_open_bus_r(space, 0); |
| 1244 | } |
| 1245 | |
| 1246 | void spc7110_mmio_write(running_machine &machine, UINT32 addr, UINT8 data) |
| 1247 | { |
| 1248 | UINT8 *ROM = machine.root_device().memregion("cart")->base(); |
| 1249 | |
| 1250 | addr &= 0xffff; |
| 1251 | |
| 1252 | switch(addr) |
| 1253 | { |
| 1254 | //================== |
| 1255 | //decompression unit |
| 1256 | //================== |
| 1257 | |
| 1258 | case 0x4801: snes_spc7110.r4801 = data; break; |
| 1259 | case 0x4802: snes_spc7110.r4802 = data; break; |
| 1260 | case 0x4803: snes_spc7110.r4803 = data; break; |
| 1261 | case 0x4804: snes_spc7110.r4804 = data; break; |
| 1262 | case 0x4805: snes_spc7110.r4805 = data; break; |
| 1263 | case 0x4806: |
| 1264 | { |
| 1265 | UINT32 table, index, address, mode, offset; |
| 1266 | snes_spc7110.r4806 = data; |
| 1267 | |
| 1268 | table = (snes_spc7110.r4801 + (snes_spc7110.r4802 << 8) + (snes_spc7110.r4803 << 16)); |
| 1269 | index = (snes_spc7110.r4804 << 2); |
| 1270 | //length = (snes_spc7110.r4809 + (snes_spc7110.r480a << 8)); |
| 1271 | address = spc7110_datarom_addr(table + index); |
| 1272 | mode = (ROM[address + 0]); |
| 1273 | offset = (ROM[address + 1] << 16) |
| 1274 | + (ROM[address + 2] << 8) |
| 1275 | + (ROM[address + 3] << 0); |
| 1276 | |
| 1277 | snes_spc7110.decomp->init(machine, ROM, mode, offset, (snes_spc7110.r4805 + (snes_spc7110.r4806 << 8)) << mode); |
| 1278 | snes_spc7110.r480c = 0x80; |
| 1279 | } |
| 1280 | break; |
| 1281 | |
| 1282 | case 0x4807: snes_spc7110.r4807 = data; break; |
| 1283 | case 0x4808: snes_spc7110.r4808 = data; break; |
| 1284 | case 0x4809: snes_spc7110.r4809 = data; break; |
| 1285 | case 0x480a: snes_spc7110.r480a = data; break; |
| 1286 | case 0x480b: snes_spc7110.r480b = data; break; |
| 1287 | |
| 1288 | //============== |
| 1289 | //data port unit |
| 1290 | //============== |
| 1291 | |
| 1292 | case 0x4811: snes_spc7110.r4811 = data; snes_spc7110.r481x |= 0x01; break; |
| 1293 | case 0x4812: snes_spc7110.r4812 = data; snes_spc7110.r481x |= 0x02; break; |
| 1294 | case 0x4813: snes_spc7110.r4813 = data; snes_spc7110.r481x |= 0x04; break; |
| 1295 | case 0x4814: |
| 1296 | { |
| 1297 | snes_spc7110.r4814 = data; |
| 1298 | snes_spc7110.r4814_latch = 1; |
| 1299 | if (!snes_spc7110.r4815_latch) |
| 1300 | { |
| 1301 | break; |
| 1302 | } |
| 1303 | if (!(snes_spc7110.r4818 & 2)) |
| 1304 | { |
| 1305 | break; |
| 1306 | } |
| 1307 | if (snes_spc7110.r4818 & 0x10) |
| 1308 | { |
| 1309 | break; |
| 1310 | } |
| 1311 | |
| 1312 | if ((snes_spc7110.r4818 & 0x60) == 0x20) |
| 1313 | { |
| 1314 | UINT32 increment = spc7110_data_adjust() & 0xff; |
| 1315 | if (snes_spc7110.r4818 & 8) |
| 1316 | { |
| 1317 | increment = (INT8)increment; //8-bit sign extend |
| 1318 | } |
| 1319 | spc7110_set_data_pointer(spc7110_data_pointer() + increment); |
| 1320 | } |
| 1321 | else if ((snes_spc7110.r4818 & 0x60) == 0x40) |
| 1322 | { |
| 1323 | UINT32 increment = spc7110_data_adjust(); |
| 1324 | if (snes_spc7110.r4818 & 8) |
| 1325 | { |
| 1326 | increment = (INT16)increment; //16-bit sign extend |
| 1327 | } |
| 1328 | spc7110_set_data_pointer(spc7110_data_pointer() + increment); |
| 1329 | } |
| 1330 | break; |
| 1331 | } |
| 1332 | |
| 1333 | case 0x4815: |
| 1334 | { |
| 1335 | snes_spc7110.r4815 = data; |
| 1336 | snes_spc7110.r4815_latch = 1; |
| 1337 | if (!snes_spc7110.r4814_latch) |
| 1338 | { |
| 1339 | break; |
| 1340 | } |
| 1341 | if (!(snes_spc7110.r4818 & 2)) |
| 1342 | { |
| 1343 | break; |
| 1344 | } |
| 1345 | if (snes_spc7110.r4818 & 0x10) |
| 1346 | { |
| 1347 | break; |
| 1348 | } |
| 1349 | |
| 1350 | if ((snes_spc7110.r4818 & 0x60) == 0x20) |
| 1351 | { |
| 1352 | UINT32 increment = spc7110_data_adjust() & 0xff; |
| 1353 | if (snes_spc7110.r4818 & 8) |
| 1354 | { |
| 1355 | increment = (INT8)increment; //8-bit sign extend |
| 1356 | } |
| 1357 | spc7110_set_data_pointer(spc7110_data_pointer() + increment); |
| 1358 | } |
| 1359 | else if ((snes_spc7110.r4818 & 0x60) == 0x40) |
| 1360 | { |
| 1361 | UINT32 increment = spc7110_data_adjust(); |
| 1362 | if (snes_spc7110.r4818 & 8) |
| 1363 | { |
| 1364 | increment = (INT16)increment; //16-bit sign extend |
| 1365 | } |
| 1366 | spc7110_set_data_pointer(spc7110_data_pointer() + increment); |
| 1367 | } |
| 1368 | break; |
| 1369 | } |
| 1370 | |
| 1371 | case 0x4816: snes_spc7110.r4816 = data; break; |
| 1372 | case 0x4817: snes_spc7110.r4817 = data; break; |
| 1373 | case 0x4818: |
| 1374 | { |
| 1375 | if (snes_spc7110.r481x != 0x07) |
| 1376 | break; |
| 1377 | |
| 1378 | snes_spc7110.r4818 = data; |
| 1379 | snes_spc7110.r4814_latch = snes_spc7110.r4815_latch = 0; |
| 1380 | break; |
| 1381 | } |
| 1382 | |
| 1383 | //========= |
| 1384 | //math unit |
| 1385 | //========= |
| 1386 | |
| 1387 | case 0x4820: snes_spc7110.r4820 = data; break; |
| 1388 | case 0x4821: snes_spc7110.r4821 = data; break; |
| 1389 | case 0x4822: snes_spc7110.r4822 = data; break; |
| 1390 | case 0x4823: snes_spc7110.r4823 = data; break; |
| 1391 | case 0x4824: snes_spc7110.r4824 = data; break; |
| 1392 | case 0x4825: |
| 1393 | { |
| 1394 | snes_spc7110.r4825 = data; |
| 1395 | |
| 1396 | if (snes_spc7110.r482e & 1) |
| 1397 | { |
| 1398 | //signed 16-bit x 16-bit multiplication |
| 1399 | INT16 r0 = (INT16)(snes_spc7110.r4824 + (snes_spc7110.r4825 << 8)); |
| 1400 | INT16 r1 = (INT16)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8)); |
| 1401 | |
| 1402 | INT32 result = r0 * r1; |
| 1403 | snes_spc7110.r4828 = result; |
| 1404 | snes_spc7110.r4829 = result >> 8; |
| 1405 | snes_spc7110.r482a = result >> 16; |
| 1406 | snes_spc7110.r482b = result >> 24; |
| 1407 | } |
| 1408 | else |
| 1409 | { |
| 1410 | //unsigned 16-bit x 16-bit multiplication |
| 1411 | UINT16 r0 = (UINT16)(snes_spc7110.r4824 + (snes_spc7110.r4825 << 8)); |
| 1412 | UINT16 r1 = (UINT16)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8)); |
| 1413 | |
| 1414 | UINT32 result = r0 * r1; |
| 1415 | snes_spc7110.r4828 = result; |
| 1416 | snes_spc7110.r4829 = result >> 8; |
| 1417 | snes_spc7110.r482a = result >> 16; |
| 1418 | snes_spc7110.r482b = result >> 24; |
| 1419 | } |
| 1420 | |
| 1421 | snes_spc7110.r482f = 0x80; |
| 1422 | break; |
| 1423 | } |
| 1424 | |
| 1425 | case 0x4826: snes_spc7110.r4826 = data; break; |
| 1426 | case 0x4827: |
| 1427 | { |
| 1428 | snes_spc7110.r4827 = data; |
| 1429 | |
| 1430 | if (snes_spc7110.r482e & 1) |
| 1431 | { |
| 1432 | //signed 32-bit x 16-bit division |
| 1433 | INT32 dividend = (INT32)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8) + (snes_spc7110.r4822 << 16) + (snes_spc7110.r4823 << 24)); |
| 1434 | INT16 divisor = (INT16)(snes_spc7110.r4826 + (snes_spc7110.r4827 << 8)); |
| 1435 | |
| 1436 | INT32 quotient; |
| 1437 | INT16 remainder; |
| 1438 | |
| 1439 | if (divisor) |
| 1440 | { |
| 1441 | quotient = (INT32)(dividend / divisor); |
| 1442 | remainder = (INT32)(dividend % divisor); |
| 1443 | } |
| 1444 | else |
| 1445 | { |
| 1446 | //illegal division by zero |
| 1447 | quotient = 0; |
| 1448 | remainder = dividend & 0xffff; |
| 1449 | } |
| 1450 | |
| 1451 | snes_spc7110.r4828 = quotient; |
| 1452 | snes_spc7110.r4829 = quotient >> 8; |
| 1453 | snes_spc7110.r482a = quotient >> 16; |
| 1454 | snes_spc7110.r482b = quotient >> 24; |
| 1455 | |
| 1456 | snes_spc7110.r482c = remainder; |
| 1457 | snes_spc7110.r482d = remainder >> 8; |
| 1458 | } |
| 1459 | else |
| 1460 | { |
| 1461 | //unsigned 32-bit x 16-bit division |
| 1462 | UINT32 dividend = (UINT32)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8) + (snes_spc7110.r4822 << 16) + (snes_spc7110.r4823 << 24)); |
| 1463 | UINT16 divisor = (UINT16)(snes_spc7110.r4826 + (snes_spc7110.r4827 << 8)); |
| 1464 | |
| 1465 | UINT32 quotient; |
| 1466 | UINT16 remainder; |
| 1467 | |
| 1468 | if (divisor) |
| 1469 | { |
| 1470 | quotient = (UINT32)(dividend / divisor); |
| 1471 | remainder = (UINT16)(dividend % divisor); |
| 1472 | } |
| 1473 | else |
| 1474 | { |
| 1475 | //illegal division by zero |
| 1476 | quotient = 0; |
| 1477 | remainder = dividend & 0xffff; |
| 1478 | } |
| 1479 | |
| 1480 | snes_spc7110.r4828 = quotient; |
| 1481 | snes_spc7110.r4829 = quotient >> 8; |
| 1482 | snes_spc7110.r482a = quotient >> 16; |
| 1483 | snes_spc7110.r482b = quotient >> 24; |
| 1484 | |
| 1485 | snes_spc7110.r482c = remainder; |
| 1486 | snes_spc7110.r482d = remainder >> 8; |
| 1487 | } |
| 1488 | |
| 1489 | snes_spc7110.r482f = 0x80; |
| 1490 | break; |
| 1491 | } |
| 1492 | |
| 1493 | case 0x482e: |
| 1494 | { |
| 1495 | //reset math unit |
| 1496 | snes_spc7110.r4820 = snes_spc7110.r4821 = snes_spc7110.r4822 = snes_spc7110.r4823 = 0; |
| 1497 | snes_spc7110.r4824 = snes_spc7110.r4825 = snes_spc7110.r4826 = snes_spc7110.r4827 = 0; |
| 1498 | snes_spc7110.r4828 = snes_spc7110.r4829 = snes_spc7110.r482a = snes_spc7110.r482b = 0; |
| 1499 | snes_spc7110.r482c = snes_spc7110.r482d = 0; |
| 1500 | |
| 1501 | snes_spc7110.r482e = data; |
| 1502 | break; |
| 1503 | } |
| 1504 | |
| 1505 | //=================== |
| 1506 | //memory mapping unit |
| 1507 | //=================== |
| 1508 | |
| 1509 | case 0x4830: snes_spc7110.r4830 = data; break; |
| 1510 | |
| 1511 | case 0x4831: |
| 1512 | { |
| 1513 | snes_spc7110.r4831 = data; |
| 1514 | snes_spc7110.dx_offset = spc7110_datarom_addr(data * 0x100000); |
| 1515 | break; |
| 1516 | } |
| 1517 | |
| 1518 | case 0x4832: |
| 1519 | { |
| 1520 | snes_spc7110.r4832 = data; |
| 1521 | snes_spc7110.ex_offset = spc7110_datarom_addr(data * 0x100000); |
| 1522 | break; |
| 1523 | } |
| 1524 | |
| 1525 | case 0x4833: |
| 1526 | { |
| 1527 | snes_spc7110.r4833 = data; |
| 1528 | snes_spc7110.fx_offset = spc7110_datarom_addr(data * 0x100000); |
| 1529 | break; |
| 1530 | } |
| 1531 | |
| 1532 | case 0x4834: snes_spc7110.r4834 = data; break; |
| 1533 | |
| 1534 | //==================== |
| 1535 | //real-time clock unit |
| 1536 | //==================== |
| 1537 | |
| 1538 | case 0x4840: |
| 1539 | { |
| 1540 | snes_spc7110.r4840 = data; |
| 1541 | |
| 1542 | if (!(snes_spc7110.r4840 & 1)) |
| 1543 | { |
| 1544 | //disable RTC |
| 1545 | snes_spc7110.rtc_state = RTCS_Inactive; |
| 1546 | spc7110_update_time(machine, 0); |
| 1547 | } |
| 1548 | else |
| 1549 | { |
| 1550 | //enable RTC |
| 1551 | snes_spc7110.r4842 = 0x80; |
| 1552 | snes_spc7110.rtc_state = RTCS_ModeSelect; |
| 1553 | } |
| 1554 | } |
| 1555 | break; |
| 1556 | |
| 1557 | case 0x4841: |
| 1558 | { |
| 1559 | snes_spc7110.r4841 = data; |
| 1560 | |
| 1561 | switch (snes_spc7110.rtc_state) |
| 1562 | { |
| 1563 | case RTCS_ModeSelect: |
| 1564 | if (data == RTCM_Linear || data == RTCM_Indexed) |
| 1565 | { |
| 1566 | snes_spc7110.r4842 = 0x80; |
| 1567 | snes_spc7110.rtc_state = RTCS_IndexSelect; |
| 1568 | snes_spc7110.rtc_mode = (RTC_Mode)data; |
| 1569 | snes_spc7110.rtc_index = 0; |
| 1570 | } |
| 1571 | break; |
| 1572 | |
| 1573 | case RTCS_IndexSelect: |
| 1574 | snes_spc7110.r4842 = 0x80; |
| 1575 | snes_spc7110.rtc_index = data & 15; |
| 1576 | if (snes_spc7110.rtc_mode == RTCM_Linear) |
| 1577 | snes_spc7110.rtc_state = RTCS_Write; |
| 1578 | break; |
| 1579 | |
| 1580 | case RTCS_Write: |
| 1581 | snes_spc7110.r4842 = 0x80; |
| 1582 | |
| 1583 | //control register 0 |
| 1584 | if (snes_spc7110.rtc_index == 13) |
| 1585 | { |
| 1586 | //increment second counter |
| 1587 | if (data & 2) |
| 1588 | spc7110_update_time(machine, 1); |
| 1589 | |
| 1590 | //round minute counter |
| 1591 | if (data & 8) |
| 1592 | { |
| 1593 | spc7110_update_time(machine, 0); |
| 1594 | |
| 1595 | UINT8 second = snes_spc7110.rtc_ram[0] + snes_spc7110.rtc_ram[1] * 10; |
| 1596 | //clear seconds |
| 1597 | snes_spc7110.rtc_ram[0] = 0; |
| 1598 | snes_spc7110.rtc_ram[1] = 0; |
| 1599 | |
| 1600 | if (second >= 30) |
| 1601 | spc7110_update_time(machine, 60); |
| 1602 | } |
| 1603 | } |
| 1604 | |
| 1605 | //control register 2 |
| 1606 | if (snes_spc7110.rtc_index == 15) |
| 1607 | { |
| 1608 | //disable timer and clear second counter |
| 1609 | if ((data & 1) && !(snes_spc7110.rtc_ram[15] & 1)) |
| 1610 | { |
| 1611 | spc7110_update_time(machine, 0); |
| 1612 | |
| 1613 | //clear seconds |
| 1614 | snes_spc7110.rtc_ram[0] = 0; |
| 1615 | snes_spc7110.rtc_ram[1] = 0; |
| 1616 | } |
| 1617 | |
| 1618 | //disable timer |
| 1619 | if ((data & 2) && !(snes_spc7110.rtc_ram[15] & 2)) |
| 1620 | spc7110_update_time(machine, 0); |
| 1621 | } |
| 1622 | |
| 1623 | snes_spc7110.rtc_ram[snes_spc7110.rtc_index] = data & 15; |
| 1624 | snes_spc7110.rtc_index = (snes_spc7110.rtc_index + 1) & 15; |
| 1625 | break; |
| 1626 | } |
| 1627 | } |
| 1628 | break; |
| 1629 | } |
| 1630 | } |
| 1631 | |
| 1632 | UINT8 spc7110_bank7_read(address_space &space, UINT32 offset) |
| 1633 | { |
| 1634 | UINT8 *ROM = space.machine().root_device().memregion("cart")->base(); |
| 1635 | UINT32 addr = offset & 0x0fffff; |
| 1636 | |
| 1637 | switch (offset & 0xf00000) |
| 1638 | { |
| 1639 | case 0x100000: |
| 1640 | return ROM[snes_spc7110.dx_offset + addr]; |
| 1641 | case 0x200000: |
| 1642 | return ROM[snes_spc7110.ex_offset + addr]; |
| 1643 | case 0x300000: |
| 1644 | return ROM[snes_spc7110.fx_offset + addr]; |
| 1645 | default: |
| 1646 | break; |
| 1647 | } |
| 1648 | return snes_open_bus_r(space, 0); |
| 1649 | } |
trunk/src/mess/machine/cx4data.c
| r0 | r21590 | |
| 1 | /*************************************************************************** |
| 2 | |
| 3 | cx4data.c |
| 4 | |
| 5 | Code based on original work by zsKnight, anomie and Nach. |
| 6 | This implementation is based on C++ "cx4*.cpp" by byuu |
| 7 | (up to date with source v 0.49). |
| 8 | |
| 9 | ***************************************************************************/ |
| 10 | |
| 11 | static const UINT8 CX4_immediate_data[48] = |
| 12 | { |
| 13 | 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, |
| 14 | 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f, |
| 15 | 0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff, |
| 16 | 0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00 |
| 17 | }; |
| 18 | |
| 19 | static const UINT16 CX4_wave_data[40] = |
| 20 | { |
| 21 | 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e, |
| 22 | 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e, |
| 23 | 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e, |
| 24 | 0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e, |
| 25 | 0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e |
| 26 | }; |
| 27 | |
| 28 | static const UINT32 CX4_sin_table[256] = |
| 29 | { |
| 30 | 0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6, |
| 31 | 0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb, |
| 32 | 0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d, |
| 33 | 0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e, |
| 34 | 0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5, |
| 35 | 0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a, |
| 36 | 0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6, |
| 37 | 0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8, |
| 38 | 0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2, |
| 39 | 0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318, |
| 40 | 0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046, |
| 41 | 0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b, |
| 42 | 0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b, |
| 43 | 0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73, |
| 44 | 0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70, |
| 45 | 0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb, |
| 46 | 0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09, |
| 47 | 0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124, |
| 48 | 0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2, |
| 49 | 0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1, |
| 50 | 0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a, |
| 51 | 0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465, |
| 52 | 0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009, |
| 53 | 0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37, |
| 54 | 0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e, |
| 55 | 0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7, |
| 56 | 0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9, |
| 57 | 0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4, |
| 58 | 0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4, |
| 59 | 0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d, |
| 60 | 0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f, |
| 61 | 0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004 |
| 62 | }; |
| 63 | |
| 64 | static const INT16 CX4_SinTable[512] = |
| 65 | { |
| 66 | 0, 402, 804, 1206, 1607, 2009, 2410, 2811, |
| 67 | 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, |
| 68 | 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, |
| 69 | 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167, |
| 70 | 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090, |
| 71 | 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869, |
| 72 | 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475, |
| 73 | 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884, |
| 74 | 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073, |
| 75 | 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020, |
| 76 | 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707, |
| 77 | 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117, |
| 78 | 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237, |
| 79 | 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057, |
| 80 | 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568, |
| 81 | 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765, |
| 82 | 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647, |
| 83 | 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214, |
| 84 | 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471, |
| 85 | 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425, |
| 86 | 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086, |
| 87 | 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466, |
| 88 | 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583, |
| 89 | 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453, |
| 90 | 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097, |
| 91 | 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537, |
| 92 | 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800, |
| 93 | 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910, |
| 94 | 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896, |
| 95 | 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786, |
| 96 | 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611, |
| 97 | 3211, 2811, 2410, 2009, 1607, 1206, 804, 402, |
| 98 | 0, -402, -804, -1206, -1607, -2009, -2410, -2811, |
| 99 | -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997, |
| 100 | -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126, |
| 101 | -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167, |
| 102 | -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090, |
| 103 | -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869, |
| 104 | -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475, |
| 105 | -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884, |
| 106 | -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073, |
| 107 | -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020, |
| 108 | -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707, |
| 109 | -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117, |
| 110 | -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237, |
| 111 | -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057, |
| 112 | -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568, |
| 113 | -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765, |
| 114 | -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647, |
| 115 | -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214, |
| 116 | -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471, |
| 117 | -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425, |
| 118 | -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086, |
| 119 | -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466, |
| 120 | -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583, |
| 121 | -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453, |
| 122 | -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097, |
| 123 | -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537, |
| 124 | -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800, |
| 125 | -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910, |
| 126 | -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896, |
| 127 | -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786, |
| 128 | -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611, |
| 129 | -3211, -2811, -2410, -2009, -1607, -1206, -804, -402 |
| 130 | }; |
| 131 | |
| 132 | static const INT16 CX4_CosTable[512] = |
| 133 | { |
| 134 | 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647, |
| 135 | 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214, |
| 136 | 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471, |
| 137 | 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425, |
| 138 | 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086, |
| 139 | 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466, |
| 140 | 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583, |
| 141 | 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453, |
| 142 | 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097, |
| 143 | 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537, |
| 144 | 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800, |
| 145 | 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910, |
| 146 | 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896, |
| 147 | 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786, |
| 148 | 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611, |
| 149 | 3211, 2811, 2410, 2009, 1607, 1206, 804, 402, |
| 150 | 0, -402, -804, -1206, -1607, -2009, -2410, -2811, |
| 151 | -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997, |
| 152 | -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126, |
| 153 | -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167, |
| 154 | -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090, |
| 155 | -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869, |
| 156 | -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475, |
| 157 | -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884, |
| 158 | -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073, |
| 159 | -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020, |
| 160 | -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707, |
| 161 | -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117, |
| 162 | -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237, |
| 163 | -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057, |
| 164 | -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568, |
| 165 | -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765, |
| 166 | -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647, |
| 167 | -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214, |
| 168 | -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471, |
| 169 | -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425, |
| 170 | -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086, |
| 171 | -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466, |
| 172 | -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583, |
| 173 | -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453, |
| 174 | -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097, |
| 175 | -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537, |
| 176 | -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800, |
| 177 | -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910, |
| 178 | -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896, |
| 179 | -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786, |
| 180 | -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611, |
| 181 | -3211, -2811, -2410, -2009, -1607, -1206, -804, -402, |
| 182 | 0, 402, 804, 1206, 1607, 2009, 2410, 2811, |
| 183 | 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, |
| 184 | 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, |
| 185 | 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167, |
| 186 | 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090, |
| 187 | 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869, |
| 188 | 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475, |
| 189 | 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884, |
| 190 | 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073, |
| 191 | 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020, |
| 192 | 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707, |
| 193 | 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117, |
| 194 | 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237, |
| 195 | 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057, |
| 196 | 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568, |
| 197 | 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765 |
| 198 | }; |
trunk/src/mess/machine/cx4fn.c
| r0 | r21590 | |
| 1 | /*************************************************************************** |
| 2 | |
| 3 | cx4fn.c |
| 4 | |
| 5 | Code based on original work by zsKnight, anomie and Nach. |
| 6 | This implementation is based on C++ "cx4*.cpp" by byuu. |
| 7 | (up to date with source v 0.49). |
| 8 | |
| 9 | ***************************************************************************/ |
| 10 | |
| 11 | #include <math.h> |
| 12 | #define CX4_Tan(a) (CX4_CosTable[a] ? ((((INT32)CX4_SinTable[a]) << 16) / CX4_CosTable[a]) : 0x80000000) |
| 13 | #define CX4_sar(b, n) ((b) >> (n)) |
| 14 | #ifdef PI |
| 15 | #undef PI |
| 16 | #endif |
| 17 | #define PI 3.1415926535897932384626433832795 |
| 18 | |
| 19 | //Wireframe Helpers |
| 20 | static void CX4_C4TransfWireFrame(void) |
| 21 | { |
| 22 | cx4.c4x = (double)cx4.C4WFXVal; |
| 23 | cx4.c4y = (double)cx4.C4WFYVal; |
| 24 | cx4.c4z = (double)cx4.C4WFZVal - 0x95; |
| 25 | |
| 26 | //Rotate X |
| 27 | cx4.tanval = -(double)cx4.C4WFX2Val * PI * 2 / 128; |
| 28 | cx4.c4y2 = cx4.c4y * cos(cx4.tanval) - cx4.c4z * sin(cx4.tanval); |
| 29 | cx4.c4z2 = cx4.c4y * sin(cx4.tanval) + cx4.c4z * cos(cx4.tanval); |
| 30 | |
| 31 | //Rotate Y |
| 32 | cx4.tanval = -(double)cx4.C4WFY2Val * PI * 2 / 128; |
| 33 | cx4.c4x2 = cx4.c4x * cos(cx4.tanval) + cx4.c4z2 * sin(cx4.tanval); |
| 34 | cx4.c4z = cx4.c4x * -sin(cx4.tanval) + cx4.c4z2 * cos(cx4.tanval); |
| 35 | |
| 36 | //Rotate Z |
| 37 | cx4.tanval = -(double)cx4.C4WFDist * PI * 2 / 128; |
| 38 | cx4.c4x = cx4.c4x2 * cos(cx4.tanval) - cx4.c4y2 * sin(cx4.tanval); |
| 39 | cx4.c4y = cx4.c4x2 * sin(cx4.tanval) + cx4.c4y2 * cos(cx4.tanval); |
| 40 | |
| 41 | //Scale |
| 42 | cx4.C4WFXVal = (INT16)(cx4.c4x * cx4.C4WFScale / (0x90 * (cx4.c4z + 0x95)) * 0x95); |
| 43 | cx4.C4WFYVal = (INT16)(cx4.c4y * cx4.C4WFScale / (0x90 * (cx4.c4z + 0x95)) * 0x95); |
| 44 | } |
| 45 | |
| 46 | static void CX4_C4CalcWireFrame(void) |
| 47 | { |
| 48 | cx4.C4WFXVal = cx4.C4WFX2Val - cx4.C4WFXVal; |
| 49 | cx4.C4WFYVal = cx4.C4WFY2Val - cx4.C4WFYVal; |
| 50 | |
| 51 | if(abs(cx4.C4WFXVal) > abs(cx4.C4WFYVal)) |
| 52 | { |
| 53 | cx4.C4WFDist = abs(cx4.C4WFXVal) + 1; |
| 54 | cx4.C4WFYVal = (256 * (long)cx4.C4WFYVal) / abs(cx4.C4WFXVal); |
| 55 | cx4.C4WFXVal = (cx4.C4WFXVal < 0) ? -256 : 256; |
| 56 | } |
| 57 | else if(cx4.C4WFYVal != 0) |
| 58 | { |
| 59 | cx4.C4WFDist = abs(cx4.C4WFYVal) + 1; |
| 60 | cx4.C4WFXVal = (256 * (long)cx4.C4WFXVal) / abs(cx4.C4WFYVal); |
| 61 | cx4.C4WFYVal = (cx4.C4WFYVal < 0) ? -256 : 256; |
| 62 | } |
| 63 | else |
| 64 | { |
| 65 | cx4.C4WFDist = 0; |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | static void CX4_C4TransfWireFrame2(void) |
| 70 | { |
| 71 | cx4.c4x = (double)cx4.C4WFXVal; |
| 72 | cx4.c4y = (double)cx4.C4WFYVal; |
| 73 | cx4.c4z = (double)cx4.C4WFZVal; |
| 74 | |
| 75 | //Rotate X |
| 76 | cx4.tanval = -(double)cx4.C4WFX2Val * PI * 2 / 128; |
| 77 | cx4.c4y2 = cx4.c4y * cos(cx4.tanval) - cx4.c4z * sin(cx4.tanval); |
| 78 | cx4.c4z2 = cx4.c4y * sin(cx4.tanval) + cx4.c4z * cos(cx4.tanval); |
| 79 | |
| 80 | //Rotate Y |
| 81 | cx4.tanval = -(double)cx4.C4WFY2Val * PI * 2 / 128; |
| 82 | cx4.c4x2 = cx4.c4x * cos(cx4.tanval) + cx4.c4z2 * sin(cx4.tanval); |
| 83 | cx4.c4z = cx4.c4x * -sin(cx4.tanval) + cx4.c4z2 * cos(cx4.tanval); |
| 84 | |
| 85 | //Rotate Z |
| 86 | cx4.tanval = -(double)cx4.C4WFDist * PI * 2 / 128; |
| 87 | cx4.c4x = cx4.c4x2 * cos(cx4.tanval) - cx4.c4y2 * sin(cx4.tanval); |
| 88 | cx4.c4y = cx4.c4x2 * sin(cx4.tanval) + cx4.c4y2 * cos(cx4.tanval); |
| 89 | |
| 90 | //Scale |
| 91 | cx4.C4WFXVal = (INT16)(cx4.c4x * cx4.C4WFScale / 0x100); |
| 92 | cx4.C4WFYVal = (INT16)(cx4.c4y * cx4.C4WFScale / 0x100); |
| 93 | } |
| 94 | |
| 95 | static void CX4_C4DrawWireFrame(running_machine &machine) |
| 96 | { |
| 97 | UINT32 line = CX4_readl(0x1f80); |
| 98 | UINT32 point1, point2; |
| 99 | INT16 X1, Y1, Z1; |
| 100 | INT16 X2, Y2, Z2; |
| 101 | UINT8 Color; |
| 102 | INT32 i; |
| 103 | |
| 104 | address_space &space = machine.device<cpu_device>("maincpu")->space(AS_PROGRAM); |
| 105 | for(i = cx4.ram[0x0295]; i > 0; i--, line += 5) |
| 106 | { |
| 107 | if(space.read_byte(line) == 0xff && |
| 108 | space.read_byte(line + 1) == 0xff) |
| 109 | { |
| 110 | INT32 tmp = line - 5; |
| 111 | while(space.read_byte(tmp + 2) == 0xff && |
| 112 | space.read_byte(tmp + 3) == 0xff && |
| 113 | (tmp + 2) >= 0) |
| 114 | { |
| 115 | tmp -= 5; |
| 116 | } |
| 117 | point1 = (CX4_read(0x1f82) << 16) | |
| 118 | (space.read_byte(tmp + 2) << 8) | |
| 119 | space.read_byte(tmp + 3); |
| 120 | } |
| 121 | else |
| 122 | { |
| 123 | point1 = (CX4_read(0x1f82) << 16) | |
| 124 | (space.read_byte(line) << 8) | |
| 125 | space.read_byte(line + 1); |
| 126 | } |
| 127 | point2 = (CX4_read(0x1f82) << 16) | |
| 128 | (space.read_byte(line + 2) << 8) | |
| 129 | space.read_byte(line + 3); |
| 130 | |
| 131 | X1=(space.read_byte(point1 + 0) << 8) | |
| 132 | space.read_byte(point1 + 1); |
| 133 | Y1=(space.read_byte(point1 + 2) << 8) | |
| 134 | space.read_byte(point1 + 3); |
| 135 | Z1=(space.read_byte(point1 + 4) << 8) | |
| 136 | space.read_byte(point1 + 5); |
| 137 | X2=(space.read_byte(point2 + 0) << 8) | |
| 138 | space.read_byte(point2 + 1); |
| 139 | Y2=(space.read_byte(point2 + 2) << 8) | |
| 140 | space.read_byte(point2 + 3); |
| 141 | Z2=(space.read_byte(point2 + 4) << 8) | |
| 142 | space.read_byte(point2 + 5); |
| 143 | Color = space.read_byte(line + 4); |
| 144 | CX4_C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color); |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | static void CX4_C4DrawLine(INT32 X1, INT32 Y1, INT16 Z1, INT32 X2, INT32 Y2, INT16 Z2, UINT8 Color) |
| 149 | { |
| 150 | INT32 i; |
| 151 | |
| 152 | //Transform coordinates |
| 153 | cx4.C4WFXVal = (INT16)X1; |
| 154 | cx4.C4WFYVal = (INT16)Y1; |
| 155 | cx4.C4WFZVal = Z1; |
| 156 | cx4.C4WFScale = CX4_read(0x1f90); |
| 157 | cx4.C4WFX2Val = CX4_read(0x1f86); |
| 158 | cx4.C4WFY2Val = CX4_read(0x1f87); |
| 159 | cx4.C4WFDist = CX4_read(0x1f88); |
| 160 | CX4_C4TransfWireFrame2(); |
| 161 | X1 = (cx4.C4WFXVal + 48) << 8; |
| 162 | Y1 = (cx4.C4WFYVal + 48) << 8; |
| 163 | |
| 164 | cx4.C4WFXVal = (INT16)X2; |
| 165 | cx4.C4WFYVal = (INT16)Y2; |
| 166 | cx4.C4WFZVal = Z2; |
| 167 | CX4_C4TransfWireFrame2(); |
| 168 | X2 = (cx4.C4WFXVal + 48) << 8; |
| 169 | Y2 = (cx4.C4WFYVal + 48) << 8; |
| 170 | |
| 171 | //Get line info |
| 172 | cx4.C4WFXVal = (INT16)(X1 >> 8); |
| 173 | cx4.C4WFYVal = (INT16)(Y1 >> 8); |
| 174 | cx4.C4WFX2Val = (INT16)(X2 >> 8); |
| 175 | cx4.C4WFY2Val = (INT16)(Y2 >> 8); |
| 176 | CX4_C4CalcWireFrame(); |
| 177 | X2 = (INT16)cx4.C4WFXVal; |
| 178 | Y2 = (INT16)cx4.C4WFYVal; |
| 179 | |
| 180 | //Render line |
| 181 | for(i = cx4.C4WFDist ? cx4.C4WFDist : 1; i > 0; i--) |
| 182 | { |
| 183 | if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) |
| 184 | { |
| 185 | UINT16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2; |
| 186 | UINT8 bit = 0x80 >> ((X1 >> 8) & 7); |
| 187 | cx4.ram[addr + 0x300] &= ~bit; |
| 188 | cx4.ram[addr + 0x301] &= ~bit; |
| 189 | if(Color & 1) |
| 190 | { |
| 191 | cx4.ram[addr + 0x300] |= bit; |
| 192 | } |
| 193 | if(Color & 2) |
| 194 | { |
| 195 | cx4.ram[addr + 0x301] |= bit; |
| 196 | } |
| 197 | } |
| 198 | X1 += X2; |
| 199 | Y1 += Y2; |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | static void CX4_C4DoScaleRotate(int row_padding) |
| 204 | { |
| 205 | INT16 A, B, C, D; |
| 206 | INT32 x, y; |
| 207 | |
| 208 | //Calculate Pixel Resolution |
| 209 | UINT8 w = CX4_read(0x1f89) & ~7; |
| 210 | UINT8 h = CX4_read(0x1f8c) & ~7; |
| 211 | |
| 212 | INT32 Cx = (INT16)CX4_readw(0x1f83); |
| 213 | INT32 Cy = (INT16)CX4_readw(0x1f86); |
| 214 | |
| 215 | INT32 LineX, LineY; |
| 216 | UINT32 X, Y; |
| 217 | UINT8 byte; |
| 218 | INT32 outidx = 0; |
| 219 | UINT8 bit = 0x80; |
| 220 | |
| 221 | //Calculate matrix |
| 222 | INT32 XScale = CX4_readw(0x1f8f); |
| 223 | INT32 YScale = CX4_readw(0x1f92); |
| 224 | |
| 225 | if(XScale & 0x8000) |
| 226 | { |
| 227 | XScale = 0x7fff; |
| 228 | } |
| 229 | if(YScale & 0x8000) |
| 230 | { |
| 231 | YScale = 0x7fff; |
| 232 | } |
| 233 | |
| 234 | if(CX4_readw(0x1f80) == 0) |
| 235 | { //no rotation |
| 236 | A = (INT16)XScale; |
| 237 | B = 0; |
| 238 | C = 0; |
| 239 | D = (INT16)YScale; |
| 240 | } |
| 241 | else if(CX4_readw(0x1f80) == 128) |
| 242 | { //90 degree rotation |
| 243 | A = 0; |
| 244 | B = (INT16)(-YScale); |
| 245 | C = (INT16)XScale; |
| 246 | D = 0; |
| 247 | } |
| 248 | else if(CX4_readw(0x1f80) == 256) |
| 249 | { //180 degree rotation |
| 250 | A = (INT16)(-XScale); |
| 251 | B = 0; |
| 252 | C = 0; |
| 253 | D = (INT16)(-YScale); |
| 254 | } |
| 255 | else if(CX4_readw(0x1f80) == 384) |
| 256 | { //270 degree rotation |
| 257 | A = 0; |
| 258 | B = (INT16)YScale; |
| 259 | C = (INT16)(-XScale); |
| 260 | D = 0; |
| 261 | } |
| 262 | else |
| 263 | { |
| 264 | A = (INT16) CX4_sar(CX4_CosTable[CX4_readw(0x1f80) & 0x1ff] * XScale, 15); |
| 265 | B = (INT16)(-CX4_sar(CX4_SinTable[CX4_readw(0x1f80) & 0x1ff] * YScale, 15)); |
| 266 | C = (INT16) CX4_sar(CX4_SinTable[CX4_readw(0x1f80) & 0x1ff] * XScale, 15); |
| 267 | D = (INT16) CX4_sar(CX4_CosTable[CX4_readw(0x1f80) & 0x1ff] * YScale, 15); |
| 268 | } |
| 269 | |
| 270 | //Clear the output RAM |
| 271 | memset(cx4.ram, 0, (w + row_padding / 4) * h / 2); |
| 272 | |
| 273 | //Calculate start position (i.e. (Ox, Oy) = (0, 0)) |
| 274 | //The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in |
| 275 | //the function. We do Cx*A etc normally because the matrix parameters |
| 276 | //already have the fractional parts. |
| 277 | LineX = (Cx << 12) - Cx * A - Cx * B; |
| 278 | LineY = (Cy << 12) - Cy * C - Cy * D; |
| 279 | |
| 280 | //Start loop |
| 281 | for(y = 0; y < h; y++) |
| 282 | { |
| 283 | X = LineX; |
| 284 | Y = LineY; |
| 285 | for(x = 0; x < w; x++) |
| 286 | { |
| 287 | if((X >> 12) >= w || (Y >> 12) >= h) |
| 288 | { |
| 289 | byte = 0; |
| 290 | } |
| 291 | else |
| 292 | { |
| 293 | UINT32 addr = (Y >> 12) * w + (X >> 12); |
| 294 | byte = CX4_read(0x600 + (addr >> 1)); |
| 295 | if(addr & 1) |
| 296 | { |
| 297 | byte >>= 4; |
| 298 | } |
| 299 | } |
| 300 | |
| 301 | //De-bitplanify |
| 302 | if(byte & 1) { cx4.ram[outidx ] |= bit; } |
| 303 | if(byte & 2) { cx4.ram[outidx + 1] |= bit; } |
| 304 | if(byte & 4) { cx4.ram[outidx + 16] |= bit; } |
| 305 | if(byte & 8) { cx4.ram[outidx + 17] |= bit; } |
| 306 | |
| 307 | bit >>= 1; |
| 308 | if(!bit) |
| 309 | { |
| 310 | bit = 0x80; |
| 311 | outidx += 32; |
| 312 | } |
| 313 | |
| 314 | X += A; //Add 1 to output x => add an A and a C |
| 315 | Y += C; |
| 316 | } |
| 317 | outidx += 2 + row_padding; |
| 318 | if(outidx & 0x10) |
| 319 | { |
| 320 | outidx &= ~0x10; |
| 321 | } |
| 322 | else |
| 323 | { |
| 324 | outidx -= w * 4 + row_padding; |
| 325 | } |
| 326 | LineX += B; //Add 1 to output y => add a B and a D |
| 327 | LineY += D; |
| 328 | } |
| 329 | } |
trunk/src/mame/machine/cx4data.c
| r21589 | r21590 | |
| 1 | | /*************************************************************************** |
| 2 | | |
| 3 | | cx4data.c |
| 4 | | |
| 5 | | Code based on original work by zsKnight, anomie and Nach. |
| 6 | | This implementation is based on C++ "cx4*.cpp" by byuu |
| 7 | | (up to date with source v 0.49). |
| 8 | | |
| 9 | | ***************************************************************************/ |
| 10 | | |
| 11 | | static const UINT8 CX4_immediate_data[48] = |
| 12 | | { |
| 13 | | 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, |
| 14 | | 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0xff, 0x7f, |
| 15 | | 0x00, 0x80, 0x00, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0xff, |
| 16 | | 0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00 |
| 17 | | }; |
| 18 | | |
| 19 | | static const UINT16 CX4_wave_data[40] = |
| 20 | | { |
| 21 | | 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000a, 0x000c, 0x000e, |
| 22 | | 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020a, 0x020c, 0x020e, |
| 23 | | 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040a, 0x040c, 0x040e, |
| 24 | | 0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060a, 0x060c, 0x060e, |
| 25 | | 0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080a, 0x080c, 0x080e |
| 26 | | }; |
| 27 | | |
| 28 | | static const UINT32 CX4_sin_table[256] = |
| 29 | | { |
| 30 | | 0x000000, 0x000324, 0x000648, 0x00096c, 0x000c8f, 0x000fb2, 0x0012d5, 0x0015f6, |
| 31 | | 0x001917, 0x001c37, 0x001f56, 0x002273, 0x002590, 0x0028aa, 0x002bc4, 0x002edb, |
| 32 | | 0x0031f1, 0x003505, 0x003817, 0x003b26, 0x003e33, 0x00413e, 0x004447, 0x00474d, |
| 33 | | 0x004a50, 0x004d50, 0x00504d, 0x005347, 0x00563e, 0x005931, 0x005c22, 0x005f0e, |
| 34 | | 0x0061f7, 0x0064dc, 0x0067bd, 0x006a9b, 0x006d74, 0x007049, 0x007319, 0x0075e5, |
| 35 | | 0x0078ad, 0x007b70, 0x007e2e, 0x0080e7, 0x00839c, 0x00864b, 0x0088f5, 0x008b9a, |
| 36 | | 0x008e39, 0x0090d3, 0x009368, 0x0095f6, 0x00987f, 0x009b02, 0x009d7f, 0x009ff6, |
| 37 | | 0x00a267, 0x00a4d2, 0x00a736, 0x00a994, 0x00abeb, 0x00ae3b, 0x00b085, 0x00b2c8, |
| 38 | | 0x00b504, 0x00b73a, 0x00b968, 0x00bb8f, 0x00bdae, 0x00bfc7, 0x00c1d8, 0x00c3e2, |
| 39 | | 0x00c5e4, 0x00c7de, 0x00c9d1, 0x00cbbb, 0x00cd9f, 0x00cf7a, 0x00d14d, 0x00d318, |
| 40 | | 0x00d4db, 0x00d695, 0x00d848, 0x00d9f2, 0x00db94, 0x00dd2d, 0x00debe, 0x00e046, |
| 41 | | 0x00e1c5, 0x00e33c, 0x00e4aa, 0x00e60f, 0x00e76b, 0x00e8bf, 0x00ea09, 0x00eb4b, |
| 42 | | 0x00ec83, 0x00edb2, 0x00eed8, 0x00eff5, 0x00f109, 0x00f213, 0x00f314, 0x00f40b, |
| 43 | | 0x00f4fa, 0x00f5de, 0x00f6ba, 0x00f78b, 0x00f853, 0x00f912, 0x00f9c7, 0x00fa73, |
| 44 | | 0x00fb14, 0x00fbac, 0x00fc3b, 0x00fcbf, 0x00fd3a, 0x00fdab, 0x00fe13, 0x00fe70, |
| 45 | | 0x00fec4, 0x00ff0e, 0x00ff4e, 0x00ff84, 0x00ffb1, 0x00ffd3, 0x00ffec, 0x00fffb, |
| 46 | | 0x000000, 0xfffcdb, 0xfff9b7, 0xfff693, 0xfff370, 0xfff04d, 0xffed2a, 0xffea09, |
| 47 | | 0xffe6e8, 0xffe3c8, 0xffe0a9, 0xffdd8c, 0xffda6f, 0xffd755, 0xffd43b, 0xffd124, |
| 48 | | 0xffce0e, 0xffcafa, 0xffc7e8, 0xffc4d9, 0xffc1cc, 0xffbec1, 0xffbbb8, 0xffb8b2, |
| 49 | | 0xffb5af, 0xffb2af, 0xffafb2, 0xffacb8, 0xffa9c1, 0xffa6ce, 0xffa3dd, 0xffa0f1, |
| 50 | | 0xff9e08, 0xff9b23, 0xff9842, 0xff9564, 0xff928b, 0xff8fb6, 0xff8ce6, 0xff8a1a, |
| 51 | | 0xff8752, 0xff848f, 0xff81d1, 0xff7f18, 0xff7c63, 0xff79b4, 0xff770a, 0xff7465, |
| 52 | | 0xff71c6, 0xff6f2c, 0xff6c97, 0xff6a09, 0xff6780, 0xff64fd, 0xff6280, 0xff6009, |
| 53 | | 0xff5d98, 0xff5b2d, 0xff58c9, 0xff566b, 0xff5414, 0xff51c4, 0xff4f7a, 0xff4d37, |
| 54 | | 0xff4afb, 0xff48c5, 0xff4697, 0xff4470, 0xff4251, 0xff4038, 0xff3e27, 0xff3c1e, |
| 55 | | 0xff3a1b, 0xff3821, 0xff362e, 0xff3444, 0xff3260, 0xff3085, 0xff2eb2, 0xff2ce7, |
| 56 | | 0xff2b24, 0xff296a, 0xff27b7, 0xff260d, 0xff246b, 0xff22d2, 0xff2141, 0xff1fb9, |
| 57 | | 0xff1e3a, 0xff1cc3, 0xff1b55, 0xff19f0, 0xff1894, 0xff1740, 0xff15f6, 0xff14b4, |
| 58 | | 0xff137c, 0xff124d, 0xff1127, 0xff100a, 0xff0ef6, 0xff0dec, 0xff0ceb, 0xff0bf4, |
| 59 | | 0xff0b05, 0xff0a21, 0xff0945, 0xff0874, 0xff07ac, 0xff06ed, 0xff0638, 0xff058d, |
| 60 | | 0xff04eb, 0xff0453, 0xff03c4, 0xff0340, 0xff02c5, 0xff0254, 0xff01ec, 0xff018f, |
| 61 | | 0xff013b, 0xff00f1, 0xff00b1, 0xff007b, 0xff004e, 0xff002c, 0xff0013, 0xff0004 |
| 62 | | }; |
| 63 | | |
| 64 | | static const INT16 CX4_SinTable[512] = |
| 65 | | { |
| 66 | | 0, 402, 804, 1206, 1607, 2009, 2410, 2811, |
| 67 | | 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, |
| 68 | | 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, |
| 69 | | 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167, |
| 70 | | 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090, |
| 71 | | 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869, |
| 72 | | 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475, |
| 73 | | 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884, |
| 74 | | 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073, |
| 75 | | 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020, |
| 76 | | 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707, |
| 77 | | 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117, |
| 78 | | 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237, |
| 79 | | 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057, |
| 80 | | 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568, |
| 81 | | 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765, |
| 82 | | 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647, |
| 83 | | 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214, |
| 84 | | 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471, |
| 85 | | 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425, |
| 86 | | 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086, |
| 87 | | 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466, |
| 88 | | 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583, |
| 89 | | 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453, |
| 90 | | 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097, |
| 91 | | 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537, |
| 92 | | 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800, |
| 93 | | 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910, |
| 94 | | 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896, |
| 95 | | 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786, |
| 96 | | 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611, |
| 97 | | 3211, 2811, 2410, 2009, 1607, 1206, 804, 402, |
| 98 | | 0, -402, -804, -1206, -1607, -2009, -2410, -2811, |
| 99 | | -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997, |
| 100 | | -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126, |
| 101 | | -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167, |
| 102 | | -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090, |
| 103 | | -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869, |
| 104 | | -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475, |
| 105 | | -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884, |
| 106 | | -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073, |
| 107 | | -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020, |
| 108 | | -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707, |
| 109 | | -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117, |
| 110 | | -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237, |
| 111 | | -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057, |
| 112 | | -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568, |
| 113 | | -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765, |
| 114 | | -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647, |
| 115 | | -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214, |
| 116 | | -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471, |
| 117 | | -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425, |
| 118 | | -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086, |
| 119 | | -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466, |
| 120 | | -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583, |
| 121 | | -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453, |
| 122 | | -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097, |
| 123 | | -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537, |
| 124 | | -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800, |
| 125 | | -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910, |
| 126 | | -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896, |
| 127 | | -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786, |
| 128 | | -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611, |
| 129 | | -3211, -2811, -2410, -2009, -1607, -1206, -804, -402 |
| 130 | | }; |
| 131 | | |
| 132 | | static const INT16 CX4_CosTable[512] = |
| 133 | | { |
| 134 | | 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647, |
| 135 | | 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214, |
| 136 | | 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471, |
| 137 | | 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425, |
| 138 | | 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086, |
| 139 | | 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466, |
| 140 | | 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583, |
| 141 | | 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453, |
| 142 | | 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097, |
| 143 | | 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537, |
| 144 | | 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800, |
| 145 | | 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910, |
| 146 | | 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896, |
| 147 | | 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786, |
| 148 | | 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611, |
| 149 | | 3211, 2811, 2410, 2009, 1607, 1206, 804, 402, |
| 150 | | 0, -402, -804, -1206, -1607, -2009, -2410, -2811, |
| 151 | | -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997, |
| 152 | | -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126, |
| 153 | | -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167, |
| 154 | | -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090, |
| 155 | | -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869, |
| 156 | | -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475, |
| 157 | | -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884, |
| 158 | | -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073, |
| 159 | | -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020, |
| 160 | | -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707, |
| 161 | | -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117, |
| 162 | | -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237, |
| 163 | | -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057, |
| 164 | | -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568, |
| 165 | | -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765, |
| 166 | | -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647, |
| 167 | | -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214, |
| 168 | | -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471, |
| 169 | | -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425, |
| 170 | | -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086, |
| 171 | | -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466, |
| 172 | | -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583, |
| 173 | | -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453, |
| 174 | | -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097, |
| 175 | | -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537, |
| 176 | | -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800, |
| 177 | | -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910, |
| 178 | | -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896, |
| 179 | | -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786, |
| 180 | | -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611, |
| 181 | | -3211, -2811, -2410, -2009, -1607, -1206, -804, -402, |
| 182 | | 0, 402, 804, 1206, 1607, 2009, 2410, 2811, |
| 183 | | 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997, |
| 184 | | 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126, |
| 185 | | 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167, |
| 186 | | 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090, |
| 187 | | 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869, |
| 188 | | 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475, |
| 189 | | 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884, |
| 190 | | 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073, |
| 191 | | 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020, |
| 192 | | 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707, |
| 193 | | 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117, |
| 194 | | 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237, |
| 195 | | 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057, |
| 196 | | 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568, |
| 197 | | 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765 |
| 198 | | }; |
trunk/src/mame/machine/snessdd1.c
| r21589 | r21590 | |
| 1 | | /*************************************************************************** |
| 2 | | |
| 3 | | snessdd1.c |
| 4 | | |
| 5 | | File to handle emulation of the SNES "S-DD1" add-on chip. |
| 6 | | |
| 7 | | Based on Andreas Naive Public Domain code. |
| 8 | | |
| 9 | | ***************************************************************************/ |
| 10 | | |
| 11 | | |
| 12 | | #define SSD1_ADD(addr)\ |
| 13 | | mmc[(addr >> 20) & 3] + (addr & 0x0fffff) |
| 14 | | |
| 15 | | class SDD1_IM //Input Manager |
| 16 | | { |
| 17 | | public: |
| 18 | | SDD1_IM() {} |
| 19 | | |
| 20 | | UINT32 m_byte_ptr; |
| 21 | | UINT8 m_bit_count; |
| 22 | | |
| 23 | | void IM_prepareDecomp(UINT32 in_buf); |
| 24 | | UINT8 IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len); |
| 25 | | }; |
| 26 | | |
| 27 | | void SDD1_IM::IM_prepareDecomp(UINT32 in_buf) |
| 28 | | { |
| 29 | | m_byte_ptr = in_buf; |
| 30 | | m_bit_count = 4; |
| 31 | | } |
| 32 | | |
| 33 | | UINT8 SDD1_IM::IM_getCodeword(UINT8 *ROM, UINT32 *mmc, const UINT8 code_len) |
| 34 | | { |
| 35 | | UINT8 codeword = ROM[SSD1_ADD(m_byte_ptr)] << m_bit_count; |
| 36 | | |
| 37 | | ++m_bit_count; |
| 38 | | |
| 39 | | if (codeword & 0x80) |
| 40 | | { |
| 41 | | codeword |= ROM[SSD1_ADD((m_byte_ptr + 1))] >> (9 - m_bit_count); |
| 42 | | m_bit_count += code_len; |
| 43 | | } |
| 44 | | |
| 45 | | if (m_bit_count & 0x08) |
| 46 | | { |
| 47 | | m_byte_ptr++; |
| 48 | | m_bit_count &= 0x07; |
| 49 | | } |
| 50 | | |
| 51 | | return codeword; |
| 52 | | } |
| 53 | | |
| 54 | | class SDD1_GCD //Golomb-Code Decoder |
| 55 | | { |
| 56 | | public: |
| 57 | | SDD1_GCD(SDD1_IM* associatedIM) |
| 58 | | : m_IM(associatedIM) { } |
| 59 | | |
| 60 | | SDD1_IM* m_IM; |
| 61 | | |
| 62 | | void GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind); |
| 63 | | }; |
| 64 | | |
| 65 | | void SDD1_GCD::GCD_getRunCount(UINT8 *ROM, UINT32 *mmc, UINT8 code_num, UINT8* MPScount, UINT8* LPSind) |
| 66 | | { |
| 67 | | const UINT8 run_count[] = |
| 68 | | { |
| 69 | | 0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00, |
| 70 | | 0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00, |
| 71 | | 0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01, |
| 72 | | 0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00, |
| 73 | | 0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03, |
| 74 | | 0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01, |
| 75 | | 0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02, |
| 76 | | 0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00, |
| 77 | | 0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07, |
| 78 | | 0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03, |
| 79 | | 0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05, |
| 80 | | 0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01, |
| 81 | | 0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06, |
| 82 | | 0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02, |
| 83 | | 0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04, |
| 84 | | 0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00, |
| 85 | | 0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f, |
| 86 | | 0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07, |
| 87 | | 0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b, |
| 88 | | 0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03, |
| 89 | | 0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d, |
| 90 | | 0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05, |
| 91 | | 0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09, |
| 92 | | 0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01, |
| 93 | | 0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e, |
| 94 | | 0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06, |
| 95 | | 0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a, |
| 96 | | 0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02, |
| 97 | | 0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c, |
| 98 | | 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, |
| 99 | | 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, |
| 100 | | 0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00, |
| 101 | | }; |
| 102 | | |
| 103 | | UINT8 codeword = m_IM->IM_getCodeword(ROM, mmc, code_num); |
| 104 | | |
| 105 | | if (codeword & 0x80) |
| 106 | | { |
| 107 | | *LPSind = 1; |
| 108 | | *MPScount = run_count[codeword >> (code_num ^ 0x07)]; |
| 109 | | } |
| 110 | | else |
| 111 | | { |
| 112 | | *MPScount = (1 << code_num); |
| 113 | | } |
| 114 | | } |
| 115 | | |
| 116 | | class SDD1_BG // Bits Generator |
| 117 | | { |
| 118 | | public: |
| 119 | | SDD1_BG(SDD1_GCD* associatedGCD, UINT8 code) |
| 120 | | : m_code_num(code), |
| 121 | | m_GCD(associatedGCD) { } |
| 122 | | |
| 123 | | UINT8 m_code_num; |
| 124 | | UINT8 m_MPScount; |
| 125 | | UINT8 m_LPSind; |
| 126 | | SDD1_GCD* m_GCD; |
| 127 | | |
| 128 | | void BG_prepareDecomp(); |
| 129 | | UINT8 BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun); |
| 130 | | } ; |
| 131 | | |
| 132 | | void SDD1_BG::BG_prepareDecomp() |
| 133 | | { |
| 134 | | m_MPScount = 0; |
| 135 | | m_LPSind = 0; |
| 136 | | } |
| 137 | | |
| 138 | | UINT8 SDD1_BG::BG_getBit(UINT8 *ROM, UINT32 *mmc, UINT8* endOfRun) |
| 139 | | { |
| 140 | | UINT8 bit; |
| 141 | | |
| 142 | | if (!(m_MPScount || m_LPSind)) |
| 143 | | { |
| 144 | | m_GCD->GCD_getRunCount(ROM, mmc, m_code_num, &(m_MPScount), &(m_LPSind)); |
| 145 | | } |
| 146 | | |
| 147 | | if (m_MPScount) |
| 148 | | { |
| 149 | | bit = 0; |
| 150 | | m_MPScount--; |
| 151 | | } |
| 152 | | else |
| 153 | | { |
| 154 | | bit = 1; |
| 155 | | m_LPSind = 0; |
| 156 | | } |
| 157 | | |
| 158 | | if (m_MPScount || m_LPSind) |
| 159 | | { |
| 160 | | (*endOfRun) = 0; |
| 161 | | } |
| 162 | | else |
| 163 | | { |
| 164 | | (*endOfRun) = 1; |
| 165 | | } |
| 166 | | |
| 167 | | return bit; |
| 168 | | } |
| 169 | | |
| 170 | | |
| 171 | | struct SDD1_PEM_state |
| 172 | | { |
| 173 | | UINT8 code_num; |
| 174 | | UINT8 nextIfMPS; |
| 175 | | UINT8 nextIfLPS; |
| 176 | | }; |
| 177 | | |
| 178 | | static const SDD1_PEM_state PEM_evolution_table[33] = |
| 179 | | { |
| 180 | | { 0,25,25}, |
| 181 | | { 0, 2, 1}, |
| 182 | | { 0, 3, 1}, |
| 183 | | { 0, 4, 2}, |
| 184 | | { 0, 5, 3}, |
| 185 | | { 1, 6, 4}, |
| 186 | | { 1, 7, 5}, |
| 187 | | { 1, 8, 6}, |
| 188 | | { 1, 9, 7}, |
| 189 | | { 2,10, 8}, |
| 190 | | { 2,11, 9}, |
| 191 | | { 2,12,10}, |
| 192 | | { 2,13,11}, |
| 193 | | { 3,14,12}, |
| 194 | | { 3,15,13}, |
| 195 | | { 3,16,14}, |
| 196 | | { 3,17,15}, |
| 197 | | { 4,18,16}, |
| 198 | | { 4,19,17}, |
| 199 | | { 5,20,18}, |
| 200 | | { 5,21,19}, |
| 201 | | { 6,22,20}, |
| 202 | | { 6,23,21}, |
| 203 | | { 7,24,22}, |
| 204 | | { 7,24,23}, |
| 205 | | { 0,26, 1}, |
| 206 | | { 1,27, 2}, |
| 207 | | { 2,28, 4}, |
| 208 | | { 3,29, 8}, |
| 209 | | { 4,30,12}, |
| 210 | | { 5,31,16}, |
| 211 | | { 6,32,18}, |
| 212 | | { 7,24,22} |
| 213 | | }; |
| 214 | | |
| 215 | | struct SDD1_PEM_ContextInfo |
| 216 | | { |
| 217 | | UINT8 status; |
| 218 | | UINT8 MPS; |
| 219 | | }; |
| 220 | | |
| 221 | | class SDD1_PEM //Probability Estimation Module |
| 222 | | { |
| 223 | | public: |
| 224 | | SDD1_PEM( |
| 225 | | SDD1_BG* associatedBG0, SDD1_BG* associatedBG1, |
| 226 | | SDD1_BG* associatedBG2, SDD1_BG* associatedBG3, |
| 227 | | SDD1_BG* associatedBG4, SDD1_BG* associatedBG5, |
| 228 | | SDD1_BG* associatedBG6, SDD1_BG* associatedBG7) |
| 229 | | { |
| 230 | | m_BG[0] = associatedBG0; |
| 231 | | m_BG[1] = associatedBG1; |
| 232 | | m_BG[2] = associatedBG2; |
| 233 | | m_BG[3] = associatedBG3; |
| 234 | | m_BG[4] = associatedBG4; |
| 235 | | m_BG[5] = associatedBG5; |
| 236 | | m_BG[6] = associatedBG6; |
| 237 | | m_BG[7] = associatedBG7; |
| 238 | | } |
| 239 | | |
| 240 | | SDD1_PEM_ContextInfo m_contextInfo[32]; |
| 241 | | SDD1_BG* m_BG[8]; |
| 242 | | |
| 243 | | void PEM_prepareDecomp(); |
| 244 | | UINT8 PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context); |
| 245 | | } ; |
| 246 | | |
| 247 | | void SDD1_PEM::PEM_prepareDecomp() |
| 248 | | { |
| 249 | | for (int i = 0; i < 32; i++) |
| 250 | | { |
| 251 | | m_contextInfo[i].status = 0; |
| 252 | | m_contextInfo[i].MPS = 0; |
| 253 | | } |
| 254 | | } |
| 255 | | |
| 256 | | UINT8 SDD1_PEM::PEM_getBit(UINT8 *ROM, UINT32 *mmc, UINT8 context) |
| 257 | | { |
| 258 | | UINT8 endOfRun; |
| 259 | | UINT8 bit; |
| 260 | | |
| 261 | | SDD1_PEM_ContextInfo *pContInfo = &(m_contextInfo)[context]; |
| 262 | | UINT8 currStatus = pContInfo->status; |
| 263 | | const SDD1_PEM_state* pState = &(PEM_evolution_table[currStatus]); |
| 264 | | UINT8 currentMPS = pContInfo->MPS; |
| 265 | | |
| 266 | | bit = m_BG[pState->code_num]->BG_getBit(ROM, mmc, &endOfRun); |
| 267 | | |
| 268 | | if (endOfRun) |
| 269 | | { |
| 270 | | if (bit) |
| 271 | | { |
| 272 | | if (!(currStatus & 0xfe)) |
| 273 | | { |
| 274 | | (pContInfo->MPS) ^= 0x01; |
| 275 | | } |
| 276 | | pContInfo->status = pState->nextIfLPS; |
| 277 | | } |
| 278 | | else |
| 279 | | { |
| 280 | | pContInfo->status = pState->nextIfMPS; |
| 281 | | } |
| 282 | | } |
| 283 | | |
| 284 | | return bit ^ currentMPS; |
| 285 | | } |
| 286 | | |
| 287 | | class SDD1_CM |
| 288 | | { |
| 289 | | public: |
| 290 | | SDD1_CM(SDD1_PEM* associatedPEM) |
| 291 | | : m_PEM(associatedPEM) { } |
| 292 | | |
| 293 | | UINT8 m_bitplanesInfo; |
| 294 | | UINT8 m_contextBitsInfo; |
| 295 | | UINT8 m_bit_number; |
| 296 | | UINT8 m_currBitplane; |
| 297 | | UINT16 m_prevBitplaneBits[8]; |
| 298 | | SDD1_PEM* m_PEM; |
| 299 | | |
| 300 | | void CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte); |
| 301 | | UINT8 CM_getBit(UINT8 *ROM, UINT32 *mmc); |
| 302 | | } ; |
| 303 | | |
| 304 | | void SDD1_CM::CM_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte) |
| 305 | | { |
| 306 | | INT32 i = 0; |
| 307 | | m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0; |
| 308 | | m_contextBitsInfo = ROM[SSD1_ADD(first_byte)] & 0x30; |
| 309 | | m_bit_number = 0; |
| 310 | | for (i = 0; i < 8; i++) |
| 311 | | { |
| 312 | | m_prevBitplaneBits[i] = 0; |
| 313 | | } |
| 314 | | switch (m_bitplanesInfo) |
| 315 | | { |
| 316 | | case 0x00: |
| 317 | | m_currBitplane = 1; |
| 318 | | break; |
| 319 | | case 0x40: |
| 320 | | m_currBitplane = 7; |
| 321 | | break; |
| 322 | | case 0x80: |
| 323 | | m_currBitplane = 3; |
| 324 | | break; |
| 325 | | } |
| 326 | | } |
| 327 | | |
| 328 | | UINT8 SDD1_CM::CM_getBit(UINT8 *ROM, UINT32 *mmc) |
| 329 | | { |
| 330 | | UINT8 currContext; |
| 331 | | UINT16 *context_bits; |
| 332 | | UINT8 bit = 0; |
| 333 | | |
| 334 | | switch (m_bitplanesInfo) |
| 335 | | { |
| 336 | | case 0x00: |
| 337 | | m_currBitplane ^= 0x01; |
| 338 | | break; |
| 339 | | case 0x40: |
| 340 | | m_currBitplane ^= 0x01; |
| 341 | | if (!(m_bit_number & 0x7f)) |
| 342 | | m_currBitplane = ((m_currBitplane + 2) & 0x07); |
| 343 | | break; |
| 344 | | case 0x80: |
| 345 | | m_currBitplane ^= 0x01; |
| 346 | | if (!(m_bit_number & 0x7f)) |
| 347 | | m_currBitplane ^= 0x02; |
| 348 | | break; |
| 349 | | case 0xc0: |
| 350 | | m_currBitplane = m_bit_number & 0x07; |
| 351 | | break; |
| 352 | | } |
| 353 | | |
| 354 | | context_bits = &(m_prevBitplaneBits)[m_currBitplane]; |
| 355 | | |
| 356 | | currContext = (m_currBitplane & 0x01) << 4; |
| 357 | | switch (m_contextBitsInfo) |
| 358 | | { |
| 359 | | case 0x00: |
| 360 | | currContext |= ((*context_bits & 0x01c0) >> 5) | (*context_bits & 0x0001); |
| 361 | | break; |
| 362 | | case 0x10: |
| 363 | | currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0001); |
| 364 | | break; |
| 365 | | case 0x20: |
| 366 | | currContext |= ((*context_bits & 0x00c0) >> 5) | (*context_bits & 0x0001); |
| 367 | | break; |
| 368 | | case 0x30: |
| 369 | | currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0003); |
| 370 | | break; |
| 371 | | } |
| 372 | | |
| 373 | | bit = m_PEM->PEM_getBit(ROM, mmc, currContext); |
| 374 | | |
| 375 | | *context_bits <<= 1; |
| 376 | | *context_bits |= bit; |
| 377 | | |
| 378 | | m_bit_number++; |
| 379 | | |
| 380 | | return bit; |
| 381 | | } |
| 382 | | |
| 383 | | class SDD1_OL |
| 384 | | { |
| 385 | | public: |
| 386 | | SDD1_OL(SDD1_CM* associatedCM) |
| 387 | | : m_CM(associatedCM) { } |
| 388 | | |
| 389 | | UINT8 m_bitplanesInfo; |
| 390 | | UINT16 m_length; |
| 391 | | UINT8* m_buffer; |
| 392 | | SDD1_CM* m_CM; |
| 393 | | |
| 394 | | void OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf); |
| 395 | | void OL_launch(UINT8 *ROM, UINT32 *mmc); |
| 396 | | } ; |
| 397 | | |
| 398 | | void SDD1_OL::OL_prepareDecomp(UINT8 *ROM, UINT32 *mmc, UINT32 first_byte, UINT16 out_len, UINT8 *out_buf) |
| 399 | | { |
| 400 | | m_bitplanesInfo = ROM[SSD1_ADD(first_byte)] & 0xc0; |
| 401 | | m_length = out_len; |
| 402 | | m_buffer = out_buf; |
| 403 | | } |
| 404 | | |
| 405 | | void SDD1_OL::OL_launch(UINT8 *ROM, UINT32 *mmc) |
| 406 | | { |
| 407 | | UINT8 i; |
| 408 | | UINT8 register1 = 0, register2 = 0; |
| 409 | | |
| 410 | | switch (m_bitplanesInfo) |
| 411 | | { |
| 412 | | case 0x00: |
| 413 | | case 0x40: |
| 414 | | case 0x80: |
| 415 | | i = 1; |
| 416 | | do |
| 417 | | { // if length == 0, we output 2^16 bytes |
| 418 | | if (!i) |
| 419 | | { |
| 420 | | *(m_buffer++) = register2; |
| 421 | | i = ~i; |
| 422 | | } |
| 423 | | else |
| 424 | | { |
| 425 | | for (register1 = register2 = 0, i = 0x80; i; i >>= 1) |
| 426 | | { |
| 427 | | if (m_CM->CM_getBit(ROM, mmc)) |
| 428 | | register1 |= i; |
| 429 | | |
| 430 | | if (m_CM->CM_getBit(ROM, mmc)) |
| 431 | | register2 |= i; |
| 432 | | } |
| 433 | | *(m_buffer++) = register1; |
| 434 | | } |
| 435 | | } while (--(m_length)); |
| 436 | | break; |
| 437 | | case 0xc0: |
| 438 | | do |
| 439 | | { |
| 440 | | for (register1 = 0, i = 0x01; i; i <<= 1) |
| 441 | | { |
| 442 | | if (m_CM->CM_getBit(ROM, mmc)) |
| 443 | | { |
| 444 | | register1 |= i; |
| 445 | | } |
| 446 | | } |
| 447 | | *(m_buffer++) = register1; |
| 448 | | } while (--(m_length)); |
| 449 | | break; |
| 450 | | } |
| 451 | | } |
| 452 | | |
| 453 | | class SDD1emu |
| 454 | | { |
| 455 | | public: |
| 456 | | SDD1emu(running_machine &machine); |
| 457 | | |
| 458 | | running_machine &machine() const { return m_machine; } |
| 459 | | |
| 460 | | SDD1_IM* m_IM; |
| 461 | | SDD1_GCD* m_GCD; |
| 462 | | SDD1_BG* m_BG0; SDD1_BG* m_BG1; SDD1_BG* m_BG2; SDD1_BG* m_BG3; |
| 463 | | SDD1_BG* m_BG4; SDD1_BG* m_BG5; SDD1_BG* m_BG6; SDD1_BG* m_BG7; |
| 464 | | SDD1_PEM* m_PEM; |
| 465 | | SDD1_CM* m_CM; |
| 466 | | SDD1_OL* m_OL; |
| 467 | | |
| 468 | | void SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf); |
| 469 | | |
| 470 | | private: |
| 471 | | running_machine& m_machine; |
| 472 | | }; |
| 473 | | |
| 474 | | SDD1emu::SDD1emu(running_machine &machine) |
| 475 | | : m_machine(machine) |
| 476 | | { |
| 477 | | m_IM = auto_alloc(machine, SDD1_IM()); |
| 478 | | m_GCD = auto_alloc(machine, SDD1_GCD(m_IM)); |
| 479 | | m_BG0 = auto_alloc(machine, SDD1_BG(m_GCD, 0)); |
| 480 | | m_BG1 = auto_alloc(machine, SDD1_BG(m_GCD, 1)); |
| 481 | | m_BG2 = auto_alloc(machine, SDD1_BG(m_GCD, 2)); |
| 482 | | m_BG3 = auto_alloc(machine, SDD1_BG(m_GCD, 3)); |
| 483 | | m_BG4 = auto_alloc(machine, SDD1_BG(m_GCD, 4)); |
| 484 | | m_BG5 = auto_alloc(machine, SDD1_BG(m_GCD, 5)); |
| 485 | | m_BG6 = auto_alloc(machine, SDD1_BG(m_GCD, 6)); |
| 486 | | m_BG7 = auto_alloc(machine, SDD1_BG(m_GCD, 7)); |
| 487 | | m_PEM = auto_alloc(machine, SDD1_PEM(m_BG0, m_BG1, m_BG2, m_BG3, |
| 488 | | m_BG4, m_BG5, m_BG6, m_BG7)); |
| 489 | | m_CM = auto_alloc(machine, SDD1_CM(m_PEM)); |
| 490 | | m_OL = auto_alloc(machine, SDD1_OL(m_CM)); |
| 491 | | } |
| 492 | | |
| 493 | | void SDD1emu::SDD1emu_decompress(UINT8 *ROM, UINT32 *mmc, UINT32 in_buf, UINT16 out_len, UINT8 *out_buf) |
| 494 | | { |
| 495 | | m_IM->IM_prepareDecomp(in_buf); |
| 496 | | m_BG0->BG_prepareDecomp(); |
| 497 | | m_BG1->BG_prepareDecomp(); |
| 498 | | m_BG2->BG_prepareDecomp(); |
| 499 | | m_BG3->BG_prepareDecomp(); |
| 500 | | m_BG4->BG_prepareDecomp(); |
| 501 | | m_BG5->BG_prepareDecomp(); |
| 502 | | m_BG6->BG_prepareDecomp(); |
| 503 | | m_BG7->BG_prepareDecomp(); |
| 504 | | m_PEM->PEM_prepareDecomp(); |
| 505 | | m_CM->CM_prepareDecomp(ROM, mmc, in_buf); |
| 506 | | m_OL->OL_prepareDecomp(ROM, mmc, in_buf, out_len, out_buf); |
| 507 | | |
| 508 | | m_OL->OL_launch(ROM, mmc); |
| 509 | | } |
| 510 | | |
| 511 | | struct snes_sdd1_t |
| 512 | | { |
| 513 | | UINT8 sdd1_enable; // channel bit-mask |
| 514 | | UINT8 xfer_enable; // channel bit-mask |
| 515 | | UINT32 mmc[4]; // memory map controller ROM indices |
| 516 | | |
| 517 | | struct |
| 518 | | { |
| 519 | | UINT32 addr; // $43x2-$43x4 -- DMA transfer address |
| 520 | | UINT16 size; // $43x5-$43x6 -- DMA transfer size |
| 521 | | } dma[8]; |
| 522 | | |
| 523 | | SDD1emu* sdd1emu; |
| 524 | | struct |
| 525 | | { |
| 526 | | UINT8 *data; // pointer to decompressed S-DD1 data (65536 bytes) |
| 527 | | UINT16 offset; // read index into S-DD1 decompression buffer |
| 528 | | UINT32 size; // length of data buffer; reads decrement counter, set ready to false at 0 |
| 529 | | UINT8 ready; // 1 when data[] is valid; 0 to invoke sdd1emu.decompress() |
| 530 | | } buffer; |
| 531 | | } ; |
| 532 | | |
| 533 | | static snes_sdd1_t snes_sdd1; |
| 534 | | |
| 535 | | void sdd1_init(running_machine& machine) |
| 536 | | { |
| 537 | | snes_sdd1.sdd1_enable = 0x00; |
| 538 | | snes_sdd1.xfer_enable = 0x00; |
| 539 | | |
| 540 | | snes_sdd1.mmc[0] = 0 << 20; |
| 541 | | snes_sdd1.mmc[1] = 1 << 20; |
| 542 | | snes_sdd1.mmc[2] = 2 << 20; |
| 543 | | snes_sdd1.mmc[3] = 3 << 20; |
| 544 | | |
| 545 | | for (int i = 0; i < 8; i++) |
| 546 | | { |
| 547 | | snes_sdd1.dma[i].addr = 0; |
| 548 | | snes_sdd1.dma[i].size = 0; |
| 549 | | } |
| 550 | | |
| 551 | | snes_sdd1.sdd1emu = auto_alloc(machine, SDD1emu(machine)); |
| 552 | | |
| 553 | | snes_sdd1.buffer.data = (UINT8*)auto_alloc_array(machine, UINT8, 0x10000); |
| 554 | | snes_sdd1.buffer.ready = 0; |
| 555 | | } |
| 556 | | |
| 557 | | UINT8 sdd1_mmio_read(address_space &space, UINT32 addr) |
| 558 | | { |
| 559 | | addr &= 0xffff; |
| 560 | | |
| 561 | | switch(addr) |
| 562 | | { |
| 563 | | case 0x4804: |
| 564 | | return (snes_sdd1.mmc[0] >> 20) & 7; |
| 565 | | case 0x4805: |
| 566 | | return (snes_sdd1.mmc[1] >> 20) & 7; |
| 567 | | case 0x4806: |
| 568 | | return (snes_sdd1.mmc[2] >> 20) & 7; |
| 569 | | case 0x4807: |
| 570 | | return (snes_sdd1.mmc[3] >> 20) & 7; |
| 571 | | } |
| 572 | | |
| 573 | | return snes_open_bus_r(space, 0); |
| 574 | | } |
| 575 | | |
| 576 | | void sdd1_mmio_write(address_space &space, UINT32 addr, UINT8 data) |
| 577 | | { |
| 578 | | addr &= 0xffff; |
| 579 | | |
| 580 | | if ((addr & 0x4380) == 0x4300) |
| 581 | | { |
| 582 | | UINT8 channel = (addr >> 4) & 7; |
| 583 | | switch(addr & 15) |
| 584 | | { |
| 585 | | case 2: |
| 586 | | snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0xffff00) + (data << 0); |
| 587 | | break; |
| 588 | | case 3: |
| 589 | | snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0xff00ff) + (data << 8); |
| 590 | | break; |
| 591 | | case 4: |
| 592 | | snes_sdd1.dma[channel].addr = (snes_sdd1.dma[channel].addr & 0x00ffff) + (data << 16); |
| 593 | | break; |
| 594 | | |
| 595 | | case 5: |
| 596 | | snes_sdd1.dma[channel].size = (snes_sdd1.dma[channel].size & 0xff00) + (data << 0); |
| 597 | | break; |
| 598 | | case 6: |
| 599 | | snes_sdd1.dma[channel].size = (snes_sdd1.dma[channel].size & 0x00ff) + (data << 8); |
| 600 | | break; |
| 601 | | } |
| 602 | | return; |
| 603 | | } |
| 604 | | |
| 605 | | switch(addr) |
| 606 | | { |
| 607 | | case 0x4800: |
| 608 | | snes_sdd1.sdd1_enable = data; |
| 609 | | break; |
| 610 | | case 0x4801: |
| 611 | | snes_sdd1.xfer_enable = data; |
| 612 | | break; |
| 613 | | |
| 614 | | case 0x4804: |
| 615 | | snes_sdd1.mmc[0] = (data & 7) << 20; |
| 616 | | break; |
| 617 | | case 0x4805: |
| 618 | | snes_sdd1.mmc[1] = (data & 7) << 20; |
| 619 | | break; |
| 620 | | case 0x4806: |
| 621 | | snes_sdd1.mmc[2] = (data & 7) << 20; |
| 622 | | break; |
| 623 | | case 0x4807: |
| 624 | | snes_sdd1.mmc[3] = (data & 7) << 20; |
| 625 | | break; |
| 626 | | } |
| 627 | | } |
| 628 | | |
| 629 | | UINT8 sdd1_read(running_machine& machine, UINT32 addr) |
| 630 | | { |
| 631 | | unsigned char *ROM = machine.root_device().memregion("cart")->base(); |
| 632 | | |
| 633 | | if (snes_sdd1.sdd1_enable & snes_sdd1.xfer_enable) |
| 634 | | { |
| 635 | | // at least one channel has S-DD1 decompression enabled... |
| 636 | | for (int i = 0; i < 8; i++) |
| 637 | | { |
| 638 | | if (snes_sdd1.sdd1_enable & snes_sdd1.xfer_enable & (1 << i)) |
| 639 | | { |
| 640 | | // S-DD1 always uses fixed transfer mode, so address will not change during transfer |
| 641 | | if ((addr + 0xc00000) == snes_sdd1.dma[i].addr) |
| 642 | | { |
| 643 | | UINT8 data; |
| 644 | | if (!snes_sdd1.buffer.ready) |
| 645 | | { |
| 646 | | UINT8 temp; |
| 647 | | // first byte read for channel performs full decompression. |
| 648 | | // this really should stream byte-by-byte, but it's not necessary since the size is known |
| 649 | | snes_sdd1.buffer.offset = 0; |
| 650 | | snes_sdd1.buffer.size = snes_sdd1.dma[i].size ? snes_sdd1.dma[i].size : 65536; |
| 651 | | |
| 652 | | // sdd1emu calls this function; it needs to access uncompressed data; |
| 653 | | // so temporarily disable decompression mode for decompress() call. |
| 654 | | temp = snes_sdd1.sdd1_enable; |
| 655 | | snes_sdd1.sdd1_enable = 0; |
| 656 | | snes_sdd1.sdd1emu->SDD1emu_decompress(ROM, snes_sdd1.mmc, addr, snes_sdd1.buffer.size, snes_sdd1.buffer.data); |
| 657 | | snes_sdd1.sdd1_enable = temp; |
| 658 | | |
| 659 | | snes_sdd1.buffer.ready = 1; |
| 660 | | } |
| 661 | | |
| 662 | | // fetch a decompressed byte; once buffer is depleted, disable channel and invalidate buffer |
| 663 | | data = snes_sdd1.buffer.data[(UINT16)snes_sdd1.buffer.offset++]; |
| 664 | | if (snes_sdd1.buffer.offset >= snes_sdd1.buffer.size) |
| 665 | | { |
| 666 | | snes_sdd1.buffer.ready = 0; |
| 667 | | snes_sdd1.xfer_enable &= ~(1 << i); |
| 668 | | } |
| 669 | | |
| 670 | | return data; |
| 671 | | } // address matched |
| 672 | | } // channel enabled |
| 673 | | } // channel loop |
| 674 | | } // S-DD1 decompressor enabled |
| 675 | | |
| 676 | | return ROM[snes_sdd1.mmc[(addr >> 20) & 3] + (addr & 0x0fffff)]; |
| 677 | | } |
trunk/src/mame/machine/cx4fn.c
| r21589 | r21590 | |
| 1 | | /*************************************************************************** |
| 2 | | |
| 3 | | cx4fn.c |
| 4 | | |
| 5 | | Code based on original work by zsKnight, anomie and Nach. |
| 6 | | This implementation is based on C++ "cx4*.cpp" by byuu. |
| 7 | | (up to date with source v 0.49). |
| 8 | | |
| 9 | | ***************************************************************************/ |
| 10 | | |
| 11 | | #include <math.h> |
| 12 | | #define CX4_Tan(a) (CX4_CosTable[a] ? ((((INT32)CX4_SinTable[a]) << 16) / CX4_CosTable[a]) : 0x80000000) |
| 13 | | #define CX4_sar(b, n) ((b) >> (n)) |
| 14 | | #ifdef PI |
| 15 | | #undef PI |
| 16 | | #endif |
| 17 | | #define PI 3.1415926535897932384626433832795 |
| 18 | | |
| 19 | | //Wireframe Helpers |
| 20 | | static void CX4_C4TransfWireFrame(void) |
| 21 | | { |
| 22 | | cx4.c4x = (double)cx4.C4WFXVal; |
| 23 | | cx4.c4y = (double)cx4.C4WFYVal; |
| 24 | | cx4.c4z = (double)cx4.C4WFZVal - 0x95; |
| 25 | | |
| 26 | | //Rotate X |
| 27 | | cx4.tanval = -(double)cx4.C4WFX2Val * PI * 2 / 128; |
| 28 | | cx4.c4y2 = cx4.c4y * cos(cx4.tanval) - cx4.c4z * sin(cx4.tanval); |
| 29 | | cx4.c4z2 = cx4.c4y * sin(cx4.tanval) + cx4.c4z * cos(cx4.tanval); |
| 30 | | |
| 31 | | //Rotate Y |
| 32 | | cx4.tanval = -(double)cx4.C4WFY2Val * PI * 2 / 128; |
| 33 | | cx4.c4x2 = cx4.c4x * cos(cx4.tanval) + cx4.c4z2 * sin(cx4.tanval); |
| 34 | | cx4.c4z = cx4.c4x * -sin(cx4.tanval) + cx4.c4z2 * cos(cx4.tanval); |
| 35 | | |
| 36 | | //Rotate Z |
| 37 | | cx4.tanval = -(double)cx4.C4WFDist * PI * 2 / 128; |
| 38 | | cx4.c4x = cx4.c4x2 * cos(cx4.tanval) - cx4.c4y2 * sin(cx4.tanval); |
| 39 | | cx4.c4y = cx4.c4x2 * sin(cx4.tanval) + cx4.c4y2 * cos(cx4.tanval); |
| 40 | | |
| 41 | | //Scale |
| 42 | | cx4.C4WFXVal = (INT16)(cx4.c4x * cx4.C4WFScale / (0x90 * (cx4.c4z + 0x95)) * 0x95); |
| 43 | | cx4.C4WFYVal = (INT16)(cx4.c4y * cx4.C4WFScale / (0x90 * (cx4.c4z + 0x95)) * 0x95); |
| 44 | | } |
| 45 | | |
| 46 | | static void CX4_C4CalcWireFrame(void) |
| 47 | | { |
| 48 | | cx4.C4WFXVal = cx4.C4WFX2Val - cx4.C4WFXVal; |
| 49 | | cx4.C4WFYVal = cx4.C4WFY2Val - cx4.C4WFYVal; |
| 50 | | |
| 51 | | if(abs(cx4.C4WFXVal) > abs(cx4.C4WFYVal)) |
| 52 | | { |
| 53 | | cx4.C4WFDist = abs(cx4.C4WFXVal) + 1; |
| 54 | | cx4.C4WFYVal = (256 * (long)cx4.C4WFYVal) / abs(cx4.C4WFXVal); |
| 55 | | cx4.C4WFXVal = (cx4.C4WFXVal < 0) ? -256 : 256; |
| 56 | | } |
| 57 | | else if(cx4.C4WFYVal != 0) |
| 58 | | { |
| 59 | | cx4.C4WFDist = abs(cx4.C4WFYVal) + 1; |
| 60 | | cx4.C4WFXVal = (256 * (long)cx4.C4WFXVal) / abs(cx4.C4WFYVal); |
| 61 | | cx4.C4WFYVal = (cx4.C4WFYVal < 0) ? -256 : 256; |
| 62 | | } |
| 63 | | else |
| 64 | | { |
| 65 | | cx4.C4WFDist = 0; |
| 66 | | } |
| 67 | | } |
| 68 | | |
| 69 | | static void CX4_C4TransfWireFrame2(void) |
| 70 | | { |
| 71 | | cx4.c4x = (double)cx4.C4WFXVal; |
| 72 | | cx4.c4y = (double)cx4.C4WFYVal; |
| 73 | | cx4.c4z = (double)cx4.C4WFZVal; |
| 74 | | |
| 75 | | //Rotate X |
| 76 | | cx4.tanval = -(double)cx4.C4WFX2Val * PI * 2 / 128; |
| 77 | | cx4.c4y2 = cx4.c4y * cos(cx4.tanval) - cx4.c4z * sin(cx4.tanval); |
| 78 | | cx4.c4z2 = cx4.c4y * sin(cx4.tanval) + cx4.c4z * cos(cx4.tanval); |
| 79 | | |
| 80 | | //Rotate Y |
| 81 | | cx4.tanval = -(double)cx4.C4WFY2Val * PI * 2 / 128; |
| 82 | | cx4.c4x2 = cx4.c4x * cos(cx4.tanval) + cx4.c4z2 * sin(cx4.tanval); |
| 83 | | cx4.c4z = cx4.c4x * -sin(cx4.tanval) + cx4.c4z2 * cos(cx4.tanval); |
| 84 | | |
| 85 | | //Rotate Z |
| 86 | | cx4.tanval = -(double)cx4.C4WFDist * PI * 2 / 128; |
| 87 | | cx4.c4x = cx4.c4x2 * cos(cx4.tanval) - cx4.c4y2 * sin(cx4.tanval); |
| 88 | | cx4.c4y = cx4.c4x2 * sin(cx4.tanval) + cx4.c4y2 * cos(cx4.tanval); |
| 89 | | |
| 90 | | //Scale |
| 91 | | cx4.C4WFXVal = (INT16)(cx4.c4x * cx4.C4WFScale / 0x100); |
| 92 | | cx4.C4WFYVal = (INT16)(cx4.c4y * cx4.C4WFScale / 0x100); |
| 93 | | } |
| 94 | | |
| 95 | | static void CX4_C4DrawWireFrame(running_machine &machine) |
| 96 | | { |
| 97 | | UINT32 line = CX4_readl(0x1f80); |
| 98 | | UINT32 point1, point2; |
| 99 | | INT16 X1, Y1, Z1; |
| 100 | | INT16 X2, Y2, Z2; |
| 101 | | UINT8 Color; |
| 102 | | INT32 i; |
| 103 | | |
| 104 | | address_space &space = machine.device<cpu_device>("maincpu")->space(AS_PROGRAM); |
| 105 | | for(i = cx4.ram[0x0295]; i > 0; i--, line += 5) |
| 106 | | { |
| 107 | | if(space.read_byte(line) == 0xff && |
| 108 | | space.read_byte(line + 1) == 0xff) |
| 109 | | { |
| 110 | | INT32 tmp = line - 5; |
| 111 | | while(space.read_byte(tmp + 2) == 0xff && |
| 112 | | space.read_byte(tmp + 3) == 0xff && |
| 113 | | (tmp + 2) >= 0) |
| 114 | | { |
| 115 | | tmp -= 5; |
| 116 | | } |
| 117 | | point1 = (CX4_read(0x1f82) << 16) | |
| 118 | | (space.read_byte(tmp + 2) << 8) | |
| 119 | | space.read_byte(tmp + 3); |
| 120 | | } |
| 121 | | else |
| 122 | | { |
| 123 | | point1 = (CX4_read(0x1f82) << 16) | |
| 124 | | (space.read_byte(line) << 8) | |
| 125 | | space.read_byte(line + 1); |
| 126 | | } |
| 127 | | point2 = (CX4_read(0x1f82) << 16) | |
| 128 | | (space.read_byte(line + 2) << 8) | |
| 129 | | space.read_byte(line + 3); |
| 130 | | |
| 131 | | X1=(space.read_byte(point1 + 0) << 8) | |
| 132 | | space.read_byte(point1 + 1); |
| 133 | | Y1=(space.read_byte(point1 + 2) << 8) | |
| 134 | | space.read_byte(point1 + 3); |
| 135 | | Z1=(space.read_byte(point1 + 4) << 8) | |
| 136 | | space.read_byte(point1 + 5); |
| 137 | | X2=(space.read_byte(point2 + 0) << 8) | |
| 138 | | space.read_byte(point2 + 1); |
| 139 | | Y2=(space.read_byte(point2 + 2) << 8) | |
| 140 | | space.read_byte(point2 + 3); |
| 141 | | Z2=(space.read_byte(point2 + 4) << 8) | |
| 142 | | space.read_byte(point2 + 5); |
| 143 | | Color = space.read_byte(line + 4); |
| 144 | | CX4_C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color); |
| 145 | | } |
| 146 | | } |
| 147 | | |
| 148 | | static void CX4_C4DrawLine(INT32 X1, INT32 Y1, INT16 Z1, INT32 X2, INT32 Y2, INT16 Z2, UINT8 Color) |
| 149 | | { |
| 150 | | INT32 i; |
| 151 | | |
| 152 | | //Transform coordinates |
| 153 | | cx4.C4WFXVal = (INT16)X1; |
| 154 | | cx4.C4WFYVal = (INT16)Y1; |
| 155 | | cx4.C4WFZVal = Z1; |
| 156 | | cx4.C4WFScale = CX4_read(0x1f90); |
| 157 | | cx4.C4WFX2Val = CX4_read(0x1f86); |
| 158 | | cx4.C4WFY2Val = CX4_read(0x1f87); |
| 159 | | cx4.C4WFDist = CX4_read(0x1f88); |
| 160 | | CX4_C4TransfWireFrame2(); |
| 161 | | X1 = (cx4.C4WFXVal + 48) << 8; |
| 162 | | Y1 = (cx4.C4WFYVal + 48) << 8; |
| 163 | | |
| 164 | | cx4.C4WFXVal = (INT16)X2; |
| 165 | | cx4.C4WFYVal = (INT16)Y2; |
| 166 | | cx4.C4WFZVal = Z2; |
| 167 | | CX4_C4TransfWireFrame2(); |
| 168 | | X2 = (cx4.C4WFXVal + 48) << 8; |
| 169 | | Y2 = (cx4.C4WFYVal + 48) << 8; |
| 170 | | |
| 171 | | //Get line info |
| 172 | | cx4.C4WFXVal = (INT16)(X1 >> 8); |
| 173 | | cx4.C4WFYVal = (INT16)(Y1 >> 8); |
| 174 | | cx4.C4WFX2Val = (INT16)(X2 >> 8); |
| 175 | | cx4.C4WFY2Val = (INT16)(Y2 >> 8); |
| 176 | | CX4_C4CalcWireFrame(); |
| 177 | | X2 = (INT16)cx4.C4WFXVal; |
| 178 | | Y2 = (INT16)cx4.C4WFYVal; |
| 179 | | |
| 180 | | //Render line |
| 181 | | for(i = cx4.C4WFDist ? cx4.C4WFDist : 1; i > 0; i--) |
| 182 | | { |
| 183 | | if(X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000) |
| 184 | | { |
| 185 | | UINT16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2; |
| 186 | | UINT8 bit = 0x80 >> ((X1 >> 8) & 7); |
| 187 | | cx4.ram[addr + 0x300] &= ~bit; |
| 188 | | cx4.ram[addr + 0x301] &= ~bit; |
| 189 | | if(Color & 1) |
| 190 | | { |
| 191 | | cx4.ram[addr + 0x300] |= bit; |
| 192 | | } |
| 193 | | if(Color & 2) |
| 194 | | { |
| 195 | | cx4.ram[addr + 0x301] |= bit; |
| 196 | | } |
| 197 | | } |
| 198 | | X1 += X2; |
| 199 | | Y1 += Y2; |
| 200 | | } |
| 201 | | } |
| 202 | | |
| 203 | | static void CX4_C4DoScaleRotate(int row_padding) |
| 204 | | { |
| 205 | | INT16 A, B, C, D; |
| 206 | | INT32 x, y; |
| 207 | | |
| 208 | | //Calculate Pixel Resolution |
| 209 | | UINT8 w = CX4_read(0x1f89) & ~7; |
| 210 | | UINT8 h = CX4_read(0x1f8c) & ~7; |
| 211 | | |
| 212 | | INT32 Cx = (INT16)CX4_readw(0x1f83); |
| 213 | | INT32 Cy = (INT16)CX4_readw(0x1f86); |
| 214 | | |
| 215 | | INT32 LineX, LineY; |
| 216 | | UINT32 X, Y; |
| 217 | | UINT8 byte; |
| 218 | | INT32 outidx = 0; |
| 219 | | UINT8 bit = 0x80; |
| 220 | | |
| 221 | | //Calculate matrix |
| 222 | | INT32 XScale = CX4_readw(0x1f8f); |
| 223 | | INT32 YScale = CX4_readw(0x1f92); |
| 224 | | |
| 225 | | if(XScale & 0x8000) |
| 226 | | { |
| 227 | | XScale = 0x7fff; |
| 228 | | } |
| 229 | | if(YScale & 0x8000) |
| 230 | | { |
| 231 | | YScale = 0x7fff; |
| 232 | | } |
| 233 | | |
| 234 | | if(CX4_readw(0x1f80) == 0) |
| 235 | | { //no rotation |
| 236 | | A = (INT16)XScale; |
| 237 | | B = 0; |
| 238 | | C = 0; |
| 239 | | D = (INT16)YScale; |
| 240 | | } |
| 241 | | else if(CX4_readw(0x1f80) == 128) |
| 242 | | { //90 degree rotation |
| 243 | | A = 0; |
| 244 | | B = (INT16)(-YScale); |
| 245 | | C = (INT16)XScale; |
| 246 | | D = 0; |
| 247 | | } |
| 248 | | else if(CX4_readw(0x1f80) == 256) |
| 249 | | { //180 degree rotation |
| 250 | | A = (INT16)(-XScale); |
| 251 | | B = 0; |
| 252 | | C = 0; |
| 253 | | D = (INT16)(-YScale); |
| 254 | | } |
| 255 | | else if(CX4_readw(0x1f80) == 384) |
| 256 | | { //270 degree rotation |
| 257 | | A = 0; |
| 258 | | B = (INT16)YScale; |
| 259 | | C = (INT16)(-XScale); |
| 260 | | D = 0; |
| 261 | | } |
| 262 | | else |
| 263 | | { |
| 264 | | A = (INT16) CX4_sar(CX4_CosTable[CX4_readw(0x1f80) & 0x1ff] * XScale, 15); |
| 265 | | B = (INT16)(-CX4_sar(CX4_SinTable[CX4_readw(0x1f80) & 0x1ff] * YScale, 15)); |
| 266 | | C = (INT16) CX4_sar(CX4_SinTable[CX4_readw(0x1f80) & 0x1ff] * XScale, 15); |
| 267 | | D = (INT16) CX4_sar(CX4_CosTable[CX4_readw(0x1f80) & 0x1ff] * YScale, 15); |
| 268 | | } |
| 269 | | |
| 270 | | //Clear the output RAM |
| 271 | | memset(cx4.ram, 0, (w + row_padding / 4) * h / 2); |
| 272 | | |
| 273 | | //Calculate start position (i.e. (Ox, Oy) = (0, 0)) |
| 274 | | //The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in |
| 275 | | //the function. We do Cx*A etc normally because the matrix parameters |
| 276 | | //already have the fractional parts. |
| 277 | | LineX = (Cx << 12) - Cx * A - Cx * B; |
| 278 | | LineY = (Cy << 12) - Cy * C - Cy * D; |
| 279 | | |
| 280 | | //Start loop |
| 281 | | for(y = 0; y < h; y++) |
| 282 | | { |
| 283 | | X = LineX; |
| 284 | | Y = LineY; |
| 285 | | for(x = 0; x < w; x++) |
| 286 | | { |
| 287 | | if((X >> 12) >= w || (Y >> 12) >= h) |
| 288 | | { |
| 289 | | byte = 0; |
| 290 | | } |
| 291 | | else |
| 292 | | { |
| 293 | | UINT32 addr = (Y >> 12) * w + (X >> 12); |
| 294 | | byte = CX4_read(0x600 + (addr >> 1)); |
| 295 | | if(addr & 1) |
| 296 | | { |
| 297 | | byte >>= 4; |
| 298 | | } |
| 299 | | } |
| 300 | | |
| 301 | | //De-bitplanify |
| 302 | | if(byte & 1) { cx4.ram[outidx ] |= bit; } |
| 303 | | if(byte & 2) { cx4.ram[outidx + 1] |= bit; } |
| 304 | | if(byte & 4) { cx4.ram[outidx + 16] |= bit; } |
| 305 | | if(byte & 8) { cx4.ram[outidx + 17] |= bit; } |
| 306 | | |
| 307 | | bit >>= 1; |
| 308 | | if(!bit) |
| 309 | | { |
| 310 | | bit = 0x80; |
| 311 | | outidx += 32; |
| 312 | | } |
| 313 | | |
| 314 | | X += A; //Add 1 to output x => add an A and a C |
| 315 | | Y += C; |
| 316 | | } |
| 317 | | outidx += 2 + row_padding; |
| 318 | | if(outidx & 0x10) |
| 319 | | { |
| 320 | | outidx &= ~0x10; |
| 321 | | } |
| 322 | | else |
| 323 | | { |
| 324 | | outidx -= w * 4 + row_padding; |
| 325 | | } |
| 326 | | LineX += B; //Add 1 to output y => add a B and a D |
| 327 | | LineY += D; |
| 328 | | } |
| 329 | | } |
trunk/src/mame/machine/snes7110.c
| r21589 | r21590 | |
| 1 | | /*************************************************************************** |
| 2 | | |
| 3 | | snes7110.c |
| 4 | | |
| 5 | | File to handle emulation of the SNES "SPC7110" add-on chip. |
| 6 | | |
| 7 | | Based on C++ implementation by Byuu in BSNES. |
| 8 | | |
| 9 | | Byuu's code is released under GNU General Public License |
| 10 | | version 2 as published by the Free Software Foundation. |
| 11 | | The implementation below is released under the MAME license |
| 12 | | for use in MAME, MESS and derivatives by permission of the |
| 13 | | author |
| 14 | | |
| 15 | | ***************************************************************************/ |
| 16 | | |
| 17 | | |
| 18 | | #define SPC7110_DECOMP_BUFFER_SIZE 64 |
| 19 | | |
| 20 | | static const UINT8 spc7110_evolution_table[53][4] = |
| 21 | | { |
| 22 | | { 0x5a, 1, 1, 1 }, |
| 23 | | { 0x25, 6, 2, 0 }, |
| 24 | | { 0x11, 8, 3, 0 }, |
| 25 | | { 0x08, 10, 4, 0 }, |
| 26 | | { 0x03, 12, 5, 0 }, |
| 27 | | { 0x01, 15, 5, 0 }, |
| 28 | | |
| 29 | | { 0x5a, 7, 7, 1 }, |
| 30 | | { 0x3f, 19, 8, 0 }, |
| 31 | | { 0x2c, 21, 9, 0 }, |
| 32 | | { 0x20, 22, 10, 0 }, |
| 33 | | { 0x17, 23, 11, 0 }, |
| 34 | | { 0x11, 25, 12, 0 }, |
| 35 | | { 0x0c, 26, 13, 0 }, |
| 36 | | { 0x09, 28, 14, 0 }, |
| 37 | | { 0x07, 29, 15, 0 }, |
| 38 | | { 0x05, 31, 16, 0 }, |
| 39 | | { 0x04, 32, 17, 0 }, |
| 40 | | { 0x03, 34, 18, 0 }, |
| 41 | | { 0x02, 35, 5, 0 }, |
| 42 | | |
| 43 | | { 0x5a, 20, 20, 1 }, |
| 44 | | { 0x48, 39, 21, 0 }, |
| 45 | | { 0x3a, 40, 22, 0 }, |
| 46 | | { 0x2e, 42, 23, 0 }, |
| 47 | | { 0x26, 44, 24, 0 }, |
| 48 | | { 0x1f, 45, 25, 0 }, |
| 49 | | { 0x19, 46, 26, 0 }, |
| 50 | | { 0x15, 25, 27, 0 }, |
| 51 | | { 0x11, 26, 28, 0 }, |
| 52 | | { 0x0e, 26, 29, 0 }, |
| 53 | | { 0x0b, 27, 30, 0 }, |
| 54 | | { 0x09, 28, 31, 0 }, |
| 55 | | { 0x08, 29, 32, 0 }, |
| 56 | | { 0x07, 30, 33, 0 }, |
| 57 | | { 0x05, 31, 34, 0 }, |
| 58 | | { 0x04, 33, 35, 0 }, |
| 59 | | { 0x04, 33, 36, 0 }, |
| 60 | | { 0x03, 34, 37, 0 }, |
| 61 | | { 0x02, 35, 38, 0 }, |
| 62 | | { 0x02, 36, 5, 0 }, |
| 63 | | |
| 64 | | { 0x58, 39, 40, 1 }, |
| 65 | | { 0x4d, 47, 41, 0 }, |
| 66 | | { 0x43, 48, 42, 0 }, |
| 67 | | { 0x3b, 49, 43, 0 }, |
| 68 | | { 0x34, 50, 44, 0 }, |
| 69 | | { 0x2e, 51, 45, 0 }, |
| 70 | | { 0x29, 44, 46, 0 }, |
| 71 | | { 0x25, 45, 24, 0 }, |
| 72 | | |
| 73 | | { 0x56, 47, 48, 1 }, |
| 74 | | { 0x4f, 47, 49, 0 }, |
| 75 | | { 0x47, 48, 50, 0 }, |
| 76 | | { 0x41, 49, 51, 0 }, |
| 77 | | { 0x3c, 50, 52, 0 }, |
| 78 | | { 0x37, 51, 43, 0 }, |
| 79 | | }; |
| 80 | | |
| 81 | | static const UINT8 spc7110_mode2_context_table[32][2] = |
| 82 | | { |
| 83 | | { 1, 2 }, |
| 84 | | |
| 85 | | { 3, 8 }, |
| 86 | | { 13, 14 }, |
| 87 | | |
| 88 | | { 15, 16 }, |
| 89 | | { 17, 18 }, |
| 90 | | { 19, 20 }, |
| 91 | | { 21, 22 }, |
| 92 | | { 23, 24 }, |
| 93 | | { 25, 26 }, |
| 94 | | { 25, 26 }, |
| 95 | | { 25, 26 }, |
| 96 | | { 25, 26 }, |
| 97 | | { 25, 26 }, |
| 98 | | { 27, 28 }, |
| 99 | | { 29, 30 }, |
| 100 | | |
| 101 | | { 31, 31 }, |
| 102 | | { 31, 31 }, |
| 103 | | { 31, 31 }, |
| 104 | | { 31, 31 }, |
| 105 | | { 31, 31 }, |
| 106 | | { 31, 31 }, |
| 107 | | { 31, 31 }, |
| 108 | | { 31, 31 }, |
| 109 | | { 31, 31 }, |
| 110 | | { 31, 31 }, |
| 111 | | { 31, 31 }, |
| 112 | | { 31, 31 }, |
| 113 | | { 31, 31 }, |
| 114 | | { 31, 31 }, |
| 115 | | { 31, 31 }, |
| 116 | | { 31, 31 }, |
| 117 | | |
| 118 | | { 31, 31 }, |
| 119 | | }; |
| 120 | | |
| 121 | | class SPC7110Decomp |
| 122 | | { |
| 123 | | public: |
| 124 | | SPC7110Decomp(running_machine &machine, UINT32 size); |
| 125 | | |
| 126 | | running_machine &machine() const { return m_machine; } |
| 127 | | |
| 128 | | void init(running_machine &machine, UINT8 *ROM, UINT32 mode, UINT32 offset, UINT32 index); |
| 129 | | void reset(); |
| 130 | | |
| 131 | | UINT8 read(UINT8 *ROM); |
| 132 | | void write(UINT8 data); |
| 133 | | void mode0(UINT8 init, UINT8 *ROM); |
| 134 | | void mode1(UINT8 init, UINT8 *ROM); |
| 135 | | void mode2(UINT8 init, UINT8 *ROM); |
| 136 | | |
| 137 | | UINT8 dataread(UINT8 *ROM); |
| 138 | | UINT8 probability(UINT32 n); |
| 139 | | UINT8 next_lps(UINT32 n); |
| 140 | | UINT8 next_mps(UINT32 n); |
| 141 | | UINT8 toggle_invert(UINT32 n); |
| 142 | | UINT32 morton_2x8(UINT32 data); |
| 143 | | UINT32 morton_4x8(UINT32 data); |
| 144 | | |
| 145 | | UINT32 m_decomp_mode; |
| 146 | | UINT32 m_decomp_offset; |
| 147 | | |
| 148 | | UINT8 *m_decomp_buffer; |
| 149 | | UINT32 m_decomp_buffer_rdoffset; |
| 150 | | UINT32 m_decomp_buffer_wroffset; |
| 151 | | UINT32 m_decomp_buffer_length; |
| 152 | | |
| 153 | | struct ContextState |
| 154 | | { |
| 155 | | UINT8 index; |
| 156 | | UINT8 invert; |
| 157 | | } m_context[32]; |
| 158 | | |
| 159 | | UINT32 m_morton16[2][256]; |
| 160 | | UINT32 m_morton32[4][256]; |
| 161 | | |
| 162 | | |
| 163 | | private: |
| 164 | | running_machine& m_machine; |
| 165 | | UINT32 m_rom_size; |
| 166 | | }; |
| 167 | | |
| 168 | | SPC7110Decomp::SPC7110Decomp(running_machine &machine, UINT32 size) |
| 169 | | : m_machine(machine), |
| 170 | | m_rom_size(size) |
| 171 | | { |
| 172 | | m_decomp_buffer = (UINT8*)auto_alloc_array(machine, UINT8, SPC7110_DECOMP_BUFFER_SIZE); |
| 173 | | reset(); |
| 174 | | |
| 175 | | for (int i = 0; i < 256; i++) |
| 176 | | { |
| 177 | | #define map(x, y) (((i >> x) & 1) << y) |
| 178 | | //2x8-bit |
| 179 | | m_morton16[1][i] = map(7, 15) + map(6, 7) + map(5, 14) + map(4, 6) |
| 180 | | + map(3, 13) + map(2, 5) + map(1, 12) + map(0, 4); |
| 181 | | m_morton16[0][i] = map(7, 11) + map(6, 3) + map(5, 10) + map(4, 2) |
| 182 | | + map(3, 9) + map(2, 1) + map(1, 8) + map(0, 0); |
| 183 | | //4x8-bit |
| 184 | | m_morton32[3][i] = map(7, 31) + map(6, 23) + map(5, 15) + map(4, 7) |
| 185 | | + map(3, 30) + map(2, 22) + map(1, 14) + map(0, 6); |
| 186 | | m_morton32[2][i] = map(7, 29) + map(6, 21) + map(5, 13) + map(4, 5) |
| 187 | | + map(3, 28) + map(2, 20) + map(1, 12) + map(0, 4); |
| 188 | | m_morton32[1][i] = map(7, 27) + map(6, 19) + map(5, 11) + map(4, 3) |
| 189 | | + map(3, 26) + map(2, 18) + map(1, 10) + map(0, 2); |
| 190 | | m_morton32[0][i] = map(7, 25) + map(6, 17) + map(5, 9) + map(4, 1) |
| 191 | | + map(3, 24) + map(2, 16) + map(1, 8) + map(0, 0); |
| 192 | | #undef map |
| 193 | | } |
| 194 | | } |
| 195 | | |
| 196 | | void SPC7110Decomp::reset() |
| 197 | | { |
| 198 | | //mode 3 is invalid; this is treated as a special case to always return 0x00 |
| 199 | | //set to mode 3 so that reading decomp port before starting first decomp will return 0x00 |
| 200 | | m_decomp_mode = 3; |
| 201 | | |
| 202 | | m_decomp_buffer_rdoffset = 0; |
| 203 | | m_decomp_buffer_wroffset = 0; |
| 204 | | m_decomp_buffer_length = 0; |
| 205 | | } |
| 206 | | |
| 207 | | void SPC7110Decomp::init(running_machine &machine, UINT8 *ROM, UINT32 mode, UINT32 offset, UINT32 index) |
| 208 | | { |
| 209 | | m_decomp_mode = mode; |
| 210 | | m_decomp_offset = offset; |
| 211 | | |
| 212 | | m_decomp_buffer_rdoffset = 0; |
| 213 | | m_decomp_buffer_wroffset = 0; |
| 214 | | m_decomp_buffer_length = 0; |
| 215 | | |
| 216 | | //reset context states |
| 217 | | for (int i = 0; i < 32; i++) |
| 218 | | { |
| 219 | | m_context[i].index = 0; |
| 220 | | m_context[i].invert = 0; |
| 221 | | } |
| 222 | | |
| 223 | | switch (m_decomp_mode) |
| 224 | | { |
| 225 | | case 0: mode0(1, ROM); break; |
| 226 | | case 1: mode1(1, ROM); break; |
| 227 | | case 2: mode2(1, ROM); break; |
| 228 | | } |
| 229 | | |
| 230 | | //decompress up to requested output data index |
| 231 | | while (index--) |
| 232 | | { |
| 233 | | read(ROM); |
| 234 | | } |
| 235 | | } |
| 236 | | |
| 237 | | UINT8 SPC7110Decomp::read(UINT8 *ROM) |
| 238 | | { |
| 239 | | UINT8 data; |
| 240 | | |
| 241 | | if (m_decomp_buffer_length == 0) |
| 242 | | { |
| 243 | | //decompress at least (SPC7110_DECOMP_BUFFER_SIZE / 2) bytes to the buffer |
| 244 | | switch (m_decomp_mode) |
| 245 | | { |
| 246 | | case 0: |
| 247 | | mode0(0, ROM); |
| 248 | | break; |
| 249 | | |
| 250 | | case 1: |
| 251 | | mode1(0, ROM); |
| 252 | | break; |
| 253 | | |
| 254 | | case 2: |
| 255 | | mode2(0, ROM); |
| 256 | | break; |
| 257 | | |
| 258 | | default: |
| 259 | | return 0x00; |
| 260 | | } |
| 261 | | } |
| 262 | | |
| 263 | | data = m_decomp_buffer[m_decomp_buffer_rdoffset++]; |
| 264 | | m_decomp_buffer_rdoffset &= SPC7110_DECOMP_BUFFER_SIZE - 1; |
| 265 | | m_decomp_buffer_length--; |
| 266 | | return data; |
| 267 | | } |
| 268 | | |
| 269 | | void SPC7110Decomp::write(UINT8 data) |
| 270 | | { |
| 271 | | m_decomp_buffer[m_decomp_buffer_wroffset++] = data; |
| 272 | | m_decomp_buffer_wroffset &= SPC7110_DECOMP_BUFFER_SIZE - 1; |
| 273 | | m_decomp_buffer_length++; |
| 274 | | } |
| 275 | | |
| 276 | | UINT8 SPC7110Decomp::dataread(UINT8 *ROM) |
| 277 | | { |
| 278 | | UINT32 size = m_rom_size - 0x100000; |
| 279 | | while (m_decomp_offset >= size) |
| 280 | | { |
| 281 | | m_decomp_offset -= size; |
| 282 | | } |
| 283 | | return ROM[0x100000 + m_decomp_offset++]; |
| 284 | | } |
| 285 | | |
| 286 | | void SPC7110Decomp::mode0(UINT8 init, UINT8 *ROM) |
| 287 | | { |
| 288 | | static UINT8 val, in, span; |
| 289 | | static INT32 out, inverts, lps, in_count; |
| 290 | | |
| 291 | | if (init == 1) |
| 292 | | { |
| 293 | | out = inverts = lps = 0; |
| 294 | | span = 0xff; |
| 295 | | val = dataread(ROM); |
| 296 | | in = dataread(ROM); |
| 297 | | in_count = 8; |
| 298 | | return; |
| 299 | | } |
| 300 | | |
| 301 | | while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1)) |
| 302 | | { |
| 303 | | for (int bit = 0; bit < 8; bit++) |
| 304 | | { |
| 305 | | //get context |
| 306 | | UINT8 mask = (1 << (bit & 3)) - 1; |
| 307 | | UINT8 con = mask + ((inverts & mask) ^ (lps & mask)); |
| 308 | | UINT32 prob, mps, flag_lps; |
| 309 | | UINT32 shift = 0; |
| 310 | | if (bit > 3) |
| 311 | | { |
| 312 | | con += 15; |
| 313 | | } |
| 314 | | |
| 315 | | //get prob and mps |
| 316 | | prob = probability(con); |
| 317 | | mps = (((out >> 15) & 1) ^ m_context[con].invert); |
| 318 | | |
| 319 | | //get bit |
| 320 | | if (val <= span - prob) //mps |
| 321 | | { |
| 322 | | span = span - prob; |
| 323 | | out = (out << 1) + mps; |
| 324 | | flag_lps = 0; |
| 325 | | } |
| 326 | | else //lps |
| 327 | | { |
| 328 | | val = val - (span - (prob - 1)); |
| 329 | | span = prob - 1; |
| 330 | | out = (out << 1) + 1 - mps; |
| 331 | | flag_lps = 1; |
| 332 | | } |
| 333 | | |
| 334 | | //renormalize |
| 335 | | while (span < 0x7f) |
| 336 | | { |
| 337 | | shift++; |
| 338 | | |
| 339 | | span = (span << 1) + 1; |
| 340 | | val = (val << 1) + (in >> 7); |
| 341 | | |
| 342 | | in <<= 1; |
| 343 | | if (--in_count == 0) |
| 344 | | { |
| 345 | | in = dataread(ROM); |
| 346 | | in_count = 8; |
| 347 | | } |
| 348 | | } |
| 349 | | |
| 350 | | //update processing info |
| 351 | | lps = (lps << 1) + flag_lps; |
| 352 | | inverts = (inverts << 1) + m_context[con].invert; |
| 353 | | |
| 354 | | //update context state |
| 355 | | if (flag_lps & toggle_invert(con)) |
| 356 | | { |
| 357 | | m_context[con].invert ^= 1; |
| 358 | | } |
| 359 | | if (flag_lps) |
| 360 | | { |
| 361 | | m_context[con].index = next_lps(con); |
| 362 | | } |
| 363 | | else if (shift) |
| 364 | | { |
| 365 | | m_context[con].index = next_mps(con); |
| 366 | | } |
| 367 | | } |
| 368 | | |
| 369 | | //save byte |
| 370 | | write(out); |
| 371 | | } |
| 372 | | } |
| 373 | | |
| 374 | | void SPC7110Decomp::mode1(UINT8 init, UINT8 *ROM) |
| 375 | | { |
| 376 | | static INT32 pixelorder[4], realorder[4]; |
| 377 | | static UINT8 in, val, span; |
| 378 | | static INT32 out, inverts, lps, in_count; |
| 379 | | |
| 380 | | if (init == 1) |
| 381 | | { |
| 382 | | for (int i = 0; i < 4; i++) |
| 383 | | { |
| 384 | | pixelorder[i] = i; |
| 385 | | } |
| 386 | | out = inverts = lps = 0; |
| 387 | | span = 0xff; |
| 388 | | val = dataread(ROM); |
| 389 | | in = dataread(ROM); |
| 390 | | in_count = 8; |
| 391 | | return; |
| 392 | | } |
| 393 | | |
| 394 | | while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1)) |
| 395 | | { |
| 396 | | UINT16 data; |
| 397 | | for (int pixel = 0; pixel < 8; pixel++) |
| 398 | | { |
| 399 | | //get first symbol context |
| 400 | | UINT32 a = ((out >> (1 * 2)) & 3); |
| 401 | | UINT32 b = ((out >> (7 * 2)) & 3); |
| 402 | | UINT32 c = ((out >> (8 * 2)) & 3); |
| 403 | | UINT32 con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); |
| 404 | | |
| 405 | | //update pixel order |
| 406 | | UINT32 m, n; |
| 407 | | for (m = 0; m < 4; m++) |
| 408 | | { |
| 409 | | if (pixelorder[m] == a) |
| 410 | | { |
| 411 | | break; |
| 412 | | } |
| 413 | | } |
| 414 | | for (n = m; n > 0; n--) |
| 415 | | { |
| 416 | | pixelorder[n] = pixelorder[n - 1]; |
| 417 | | } |
| 418 | | pixelorder[0] = a; |
| 419 | | |
| 420 | | //calculate the real pixel order |
| 421 | | for (m = 0; m < 4; m++) |
| 422 | | { |
| 423 | | realorder[m] = pixelorder[m]; |
| 424 | | } |
| 425 | | |
| 426 | | //rotate reference pixel c value to top |
| 427 | | for (m = 0; m < 4; m++) |
| 428 | | { |
| 429 | | if (realorder[m] == c) |
| 430 | | { |
| 431 | | break; |
| 432 | | } |
| 433 | | } |
| 434 | | for (n = m; n > 0; n--) |
| 435 | | { |
| 436 | | realorder[n] = realorder[n - 1]; |
| 437 | | } |
| 438 | | realorder[0] = c; |
| 439 | | |
| 440 | | //rotate reference pixel b value to top |
| 441 | | for (m = 0; m < 4; m++) |
| 442 | | { |
| 443 | | if (realorder[m] == b) |
| 444 | | { |
| 445 | | break; |
| 446 | | } |
| 447 | | } |
| 448 | | for (n = m; n > 0; n--) |
| 449 | | { |
| 450 | | realorder[n] = realorder[n - 1]; |
| 451 | | } |
| 452 | | realorder[0] = b; |
| 453 | | |
| 454 | | //rotate reference pixel a value to top |
| 455 | | for (m = 0; m < 4; m++) |
| 456 | | { |
| 457 | | if (realorder[m] == a) |
| 458 | | { |
| 459 | | break; |
| 460 | | } |
| 461 | | } |
| 462 | | for (n = m; n > 0; n--) |
| 463 | | { |
| 464 | | realorder[n] = realorder[n - 1]; |
| 465 | | } |
| 466 | | realorder[0] = a; |
| 467 | | |
| 468 | | //get 2 symbols |
| 469 | | for (int bit = 0; bit < 2; bit++) |
| 470 | | { |
| 471 | | //get prob |
| 472 | | UINT32 prob = probability(con); |
| 473 | | UINT32 shift = 0; |
| 474 | | |
| 475 | | //get symbol |
| 476 | | UINT32 flag_lps; |
| 477 | | if (val <= span - prob) //mps |
| 478 | | { |
| 479 | | span = span - prob; |
| 480 | | flag_lps = 0; |
| 481 | | } |
| 482 | | else //lps |
| 483 | | { |
| 484 | | val = val - (span - (prob - 1)); |
| 485 | | span = prob - 1; |
| 486 | | flag_lps = 1; |
| 487 | | } |
| 488 | | |
| 489 | | //renormalize |
| 490 | | while (span < 0x7f) |
| 491 | | { |
| 492 | | shift++; |
| 493 | | |
| 494 | | span = (span << 1) + 1; |
| 495 | | val = (val << 1) + (in >> 7); |
| 496 | | |
| 497 | | in <<= 1; |
| 498 | | if (--in_count == 0) |
| 499 | | { |
| 500 | | in = dataread(ROM); |
| 501 | | in_count = 8; |
| 502 | | } |
| 503 | | } |
| 504 | | |
| 505 | | //update processing info |
| 506 | | lps = (lps << 1) + flag_lps; |
| 507 | | inverts = (inverts << 1) + m_context[con].invert; |
| 508 | | |
| 509 | | //update context state |
| 510 | | if (flag_lps & toggle_invert(con)) |
| 511 | | { |
| 512 | | m_context[con].invert ^= 1; |
| 513 | | } |
| 514 | | if (flag_lps) |
| 515 | | { |
| 516 | | m_context[con].index = next_lps(con); |
| 517 | | } |
| 518 | | else if (shift) |
| 519 | | { |
| 520 | | m_context[con].index = next_mps(con); |
| 521 | | } |
| 522 | | |
| 523 | | //get next context |
| 524 | | con = 5 + (con << 1) + ((lps ^ inverts) & 1); |
| 525 | | } |
| 526 | | |
| 527 | | //get pixel |
| 528 | | b = realorder[(lps ^ inverts) & 3]; |
| 529 | | out = (out << 2) + b; |
| 530 | | } |
| 531 | | |
| 532 | | //turn pixel data into bitplanes |
| 533 | | data = morton_2x8(out); |
| 534 | | write(data >> 8); |
| 535 | | write(data >> 0); |
| 536 | | } |
| 537 | | } |
| 538 | | |
| 539 | | void SPC7110Decomp::mode2(UINT8 init, UINT8 *ROM) |
| 540 | | { |
| 541 | | static INT32 pixelorder[16], realorder[16]; |
| 542 | | static UINT8 bitplanebuffer[16], buffer_index; |
| 543 | | static UINT8 in, val, span; |
| 544 | | static INT32 out0, out1, inverts, lps, in_count; |
| 545 | | |
| 546 | | if (init == 1) |
| 547 | | { |
| 548 | | for (int i = 0; i < 16; i++) |
| 549 | | { |
| 550 | | pixelorder[i] = i; |
| 551 | | } |
| 552 | | buffer_index = 0; |
| 553 | | out0 = out1 = inverts = lps = 0; |
| 554 | | span = 0xff; |
| 555 | | val = dataread(ROM); |
| 556 | | in = dataread(ROM); |
| 557 | | in_count = 8; |
| 558 | | return; |
| 559 | | } |
| 560 | | |
| 561 | | while (m_decomp_buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1)) |
| 562 | | { |
| 563 | | UINT32 data; |
| 564 | | for (int pixel = 0; pixel < 8; pixel++) |
| 565 | | { |
| 566 | | //get first symbol context |
| 567 | | UINT32 a = ((out0 >> (0 * 4)) & 15); |
| 568 | | UINT32 b = ((out0 >> (7 * 4)) & 15); |
| 569 | | UINT32 c = ((out1 >> (0 * 4)) & 15); |
| 570 | | UINT32 con = 0; |
| 571 | | UINT32 refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c); |
| 572 | | |
| 573 | | //update pixel order |
| 574 | | UINT32 m, n; |
| 575 | | for (m = 0; m < 16; m++) |
| 576 | | { |
| 577 | | if (pixelorder[m] == a) |
| 578 | | { |
| 579 | | break; |
| 580 | | } |
| 581 | | } |
| 582 | | for (n = m; n > 0; n--) |
| 583 | | { |
| 584 | | pixelorder[n] = pixelorder[n - 1]; |
| 585 | | } |
| 586 | | pixelorder[0] = a; |
| 587 | | |
| 588 | | //calculate the real pixel order |
| 589 | | for (m = 0; m < 16; m++) |
| 590 | | { |
| 591 | | realorder[m] = pixelorder[m]; |
| 592 | | } |
| 593 | | |
| 594 | | //rotate reference pixel c value to top |
| 595 | | for (m = 0; m < 16; m++) |
| 596 | | { |
| 597 | | if (realorder[m] == c) |
| 598 | | { |
| 599 | | break; |
| 600 | | } |
| 601 | | } |
| 602 | | for (n = m; n > 0; n--) |
| 603 | | { |
| 604 | | realorder[n] = realorder[n - 1]; |
| 605 | | } |
| 606 | | realorder[0] = c; |
| 607 | | |
| 608 | | //rotate reference pixel b value to top |
| 609 | | for (m = 0; m < 16; m++) |
| 610 | | { |
| 611 | | if (realorder[m] == b) |
| 612 | | { |
| 613 | | break; |
| 614 | | } |
| 615 | | } |
| 616 | | for (n = m; n > 0; n--) |
| 617 | | { |
| 618 | | realorder[n] = realorder[n - 1]; |
| 619 | | } |
| 620 | | realorder[0] = b; |
| 621 | | |
| 622 | | //rotate reference pixel a value to top |
| 623 | | for (m = 0; m < 16; m++) |
| 624 | | { |
| 625 | | if (realorder[m] == a) |
| 626 | | { |
| 627 | | break; |
| 628 | | } |
| 629 | | } |
| 630 | | for (n = m; n > 0; n--) |
| 631 | | { |
| 632 | | realorder[n] = realorder[n - 1]; |
| 633 | | } |
| 634 | | realorder[0] = a; |
| 635 | | |
| 636 | | //get 4 symbols |
| 637 | | for (int bit = 0; bit < 4; bit++) |
| 638 | | { |
| 639 | | UINT32 invertbit, shift; |
| 640 | | |
| 641 | | //get prob |
| 642 | | UINT32 prob = probability(con); |
| 643 | | |
| 644 | | //get symbol |
| 645 | | UINT32 flag_lps; |
| 646 | | if (val <= span - prob) //mps |
| 647 | | { |
| 648 | | span = span - prob; |
| 649 | | flag_lps = 0; |
| 650 | | } |
| 651 | | else //lps |
| 652 | | { |
| 653 | | val = val - (span - (prob - 1)); |
| 654 | | span = prob - 1; |
| 655 | | flag_lps = 1; |
| 656 | | } |
| 657 | | |
| 658 | | //renormalize |
| 659 | | shift = 0; |
| 660 | | while (span < 0x7f) |
| 661 | | { |
| 662 | | shift++; |
| 663 | | |
| 664 | | span = (span << 1) + 1; |
| 665 | | val = (val << 1) + (in >> 7); |
| 666 | | |
| 667 | | in <<= 1; |
| 668 | | if (--in_count == 0) |
| 669 | | { |
| 670 | | in = dataread(ROM); |
| 671 | | in_count = 8; |
| 672 | | } |
| 673 | | } |
| 674 | | |
| 675 | | //update processing info |
| 676 | | lps = (lps << 1) + flag_lps; |
| 677 | | invertbit = m_context[con].invert; |
| 678 | | inverts = (inverts << 1) + invertbit; |
| 679 | | |
| 680 | | //update context state |
| 681 | | if (flag_lps & toggle_invert(con)) |
| 682 | | { |
| 683 | | m_context[con].invert ^= 1; |
| 684 | | } |
| 685 | | if (flag_lps) |
| 686 | | { |
| 687 | | m_context[con].index = next_lps(con); |
| 688 | | } |
| 689 | | else if (shift) |
| 690 | | { |
| 691 | | m_context[con].index = next_mps(con); |
| 692 | | } |
| 693 | | |
| 694 | | //get next context |
| 695 | | con = spc7110_mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0); |
| 696 | | } |
| 697 | | |
| 698 | | //get pixel |
| 699 | | b = realorder[(lps ^ inverts) & 0x0f]; |
| 700 | | out1 = (out1 << 4) + ((out0 >> 28) & 0x0f); |
| 701 | | out0 = (out0 << 4) + b; |
| 702 | | } |
| 703 | | |
| 704 | | //convert pixel data into bitplanes |
| 705 | | data = morton_4x8(out0); |
| 706 | | write(data >> 24); |
| 707 | | write(data >> 16); |
| 708 | | bitplanebuffer[buffer_index++] = data >> 8; |
| 709 | | bitplanebuffer[buffer_index++] = data >> 0; |
| 710 | | |
| 711 | | if (buffer_index == 16) |
| 712 | | { |
| 713 | | for (int i = 0; i < 16; i++) |
| 714 | | { |
| 715 | | write(bitplanebuffer[i]); |
| 716 | | } |
| 717 | | buffer_index = 0; |
| 718 | | } |
| 719 | | } |
| 720 | | } |
| 721 | | |
| 722 | | UINT8 SPC7110Decomp::probability(UINT32 n) |
| 723 | | { |
| 724 | | return spc7110_evolution_table[m_context[n].index][0]; |
| 725 | | } |
| 726 | | |
| 727 | | UINT8 SPC7110Decomp::next_lps(UINT32 n) |
| 728 | | { |
| 729 | | return spc7110_evolution_table[m_context[n].index][1]; |
| 730 | | } |
| 731 | | |
| 732 | | UINT8 SPC7110Decomp::next_mps(UINT32 n) |
| 733 | | { |
| 734 | | return spc7110_evolution_table[m_context[n].index][2]; |
| 735 | | } |
| 736 | | |
| 737 | | UINT8 SPC7110Decomp::toggle_invert(UINT32 n) |
| 738 | | { |
| 739 | | return spc7110_evolution_table[m_context[n].index][3]; |
| 740 | | } |
| 741 | | |
| 742 | | UINT32 SPC7110Decomp::morton_2x8(UINT32 data) |
| 743 | | { |
| 744 | | //reverse morton lookup: de-interleave two 8-bit values |
| 745 | | //15, 13, 11, 9, 7, 5, 3, 1 -> 15- 8 |
| 746 | | //14, 12, 10, 8, 6, 4, 2, 0 -> 7- 0 |
| 747 | | return m_morton16[0][(data >> 0) & 255] + m_morton16[1][(data >> 8) & 255]; |
| 748 | | } |
| 749 | | |
| 750 | | UINT32 SPC7110Decomp::morton_4x8(UINT32 data) |
| 751 | | { |
| 752 | | //reverse morton lookup: de-interleave four 8-bit values |
| 753 | | //31, 27, 23, 19, 15, 11, 7, 3 -> 31-24 |
| 754 | | //30, 26, 22, 18, 14, 10, 6, 2 -> 23-16 |
| 755 | | //29, 25, 21, 17, 13, 9, 5, 1 -> 15- 8 |
| 756 | | //28, 24, 20, 16, 12, 8, 4, 0 -> 7- 0 |
| 757 | | return m_morton32[0][(data >> 0) & 255] + m_morton32[1][(data >> 8) & 255] |
| 758 | | + m_morton32[2][(data >> 16) & 255] + m_morton32[3][(data >> 24) & 255]; |
| 759 | | } |
| 760 | | |
| 761 | | static void spc7110_update_time(running_machine &machine, UINT8 offset); |
| 762 | | |
| 763 | | enum RTC_State |
| 764 | | { |
| 765 | | RTCS_Inactive, |
| 766 | | RTCS_ModeSelect, |
| 767 | | RTCS_IndexSelect, |
| 768 | | RTCS_Write |
| 769 | | }; |
| 770 | | |
| 771 | | enum RTC_Mode |
| 772 | | { |
| 773 | | RTCM_Linear = 0x03, |
| 774 | | RTCM_Indexed = 0x0c |
| 775 | | }; |
| 776 | | |
| 777 | | static const UINT32 spc7110_months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
| 778 | | |
| 779 | | struct snes_spc7110_t |
| 780 | | { |
| 781 | | //================== |
| 782 | | //decompression unit |
| 783 | | //================== |
| 784 | | UINT8 r4801; // compression table low |
| 785 | | UINT8 r4802; // compression table high |
| 786 | | UINT8 r4803; // compression table bank |
| 787 | | UINT8 r4804; // compression table index |
| 788 | | UINT8 r4805; // decompression buffer index low |
| 789 | | UINT8 r4806; // decompression buffer index high |
| 790 | | UINT8 r4807; // ??? |
| 791 | | UINT8 r4808; // ??? |
| 792 | | UINT8 r4809; // compression length low |
| 793 | | UINT8 r480a; // compression length high |
| 794 | | UINT8 r480b; // decompression control register |
| 795 | | UINT8 r480c; // decompression status |
| 796 | | |
| 797 | | SPC7110Decomp* decomp; |
| 798 | | |
| 799 | | UINT8 r4811; // data pointer low |
| 800 | | UINT8 r4812; // data pointer high |
| 801 | | UINT8 r4813; // data pointer bank |
| 802 | | UINT8 r4814; // data adjust low |
| 803 | | UINT8 r4815; // data adjust high |
| 804 | | UINT8 r4816; // data increment low |
| 805 | | UINT8 r4817; // data increment high |
| 806 | | UINT8 r4818; // data port control register |
| 807 | | |
| 808 | | UINT8 r481x; |
| 809 | | |
| 810 | | UINT8 r4814_latch; |
| 811 | | UINT8 r4815_latch; |
| 812 | | |
| 813 | | //========= |
| 814 | | //math unit |
| 815 | | //========= |
| 816 | | UINT8 r4820; // 16-bit multiplicand B0, 32-bit dividend B0 |
| 817 | | UINT8 r4821; // 16-bit multiplicand B1, 32-bit dividend B1 |
| 818 | | UINT8 r4822; // 32-bit dividend B2 |
| 819 | | UINT8 r4823; // 32-bit dividend B3 |
| 820 | | UINT8 r4824; // 16-bit multiplier B0 |
| 821 | | UINT8 r4825; // 16-bit multiplier B1 |
| 822 | | UINT8 r4826; // 16-bit divisor B0 |
| 823 | | UINT8 r4827; // 16-bit divisor B1 |
| 824 | | UINT8 r4828; // 32-bit product B0, 32-bit quotient B0 |
| 825 | | UINT8 r4829; // 32-bit product B1, 32-bit quotient B1 |
| 826 | | UINT8 r482a; // 32-bit product B2, 32-bit quotient B2 |
| 827 | | UINT8 r482b; // 32-bit product B3, 32-bit quotient B3 |
| 828 | | UINT8 r482c; // 16-bit remainder B0 |
| 829 | | UINT8 r482d; // 16-bit remainder B1 |
| 830 | | UINT8 r482e; // math control register |
| 831 | | UINT8 r482f; // math status |
| 832 | | |
| 833 | | //=================== |
| 834 | | //memory mapping unit |
| 835 | | //=================== |
| 836 | | UINT8 r4830; // SRAM write enable |
| 837 | | UINT8 r4831; // $[d0-df]:[0000-ffff] mapping |
| 838 | | UINT8 r4832; // $[e0-ef]:[0000-ffff] mapping |
| 839 | | UINT8 r4833; // $[f0-ff]:[0000-ffff] mapping |
| 840 | | UINT8 r4834; // ??? |
| 841 | | |
| 842 | | UINT32 dx_offset; |
| 843 | | UINT32 ex_offset; |
| 844 | | UINT32 fx_offset; |
| 845 | | |
| 846 | | //==================== |
| 847 | | //real-time clock unit |
| 848 | | //==================== |
| 849 | | UINT8 r4840; // RTC latch |
| 850 | | UINT8 r4841; // RTC index/data port |
| 851 | | UINT8 r4842; // RTC status |
| 852 | | |
| 853 | | UINT32 rtc_state; |
| 854 | | UINT32 rtc_mode; |
| 855 | | UINT32 rtc_index; |
| 856 | | |
| 857 | | UINT64 rtc_offset; |
| 858 | | |
| 859 | | UINT8 rtc_ram[16]; // 0-12 secs, min, hrs, etc.; 13-14-15 control registers |
| 860 | | |
| 861 | | UINT32 size; |
| 862 | | }; |
| 863 | | |
| 864 | | static snes_spc7110_t snes_spc7110; |
| 865 | | |
| 866 | | void spc7110_init(running_machine& machine) |
| 867 | | { |
| 868 | | snes_state *state = machine.driver_data<snes_state>(); |
| 869 | | |
| 870 | | snes_spc7110.r4801 = 0x00; |
| 871 | | snes_spc7110.r4802 = 0x00; |
| 872 | | snes_spc7110.r4803 = 0x00; |
| 873 | | snes_spc7110.r4804 = 0x00; |
| 874 | | snes_spc7110.r4805 = 0x00; |
| 875 | | snes_spc7110.r4806 = 0x00; |
| 876 | | snes_spc7110.r4807 = 0x00; |
| 877 | | snes_spc7110.r4808 = 0x00; |
| 878 | | snes_spc7110.r4809 = 0x00; |
| 879 | | snes_spc7110.r480a = 0x00; |
| 880 | | snes_spc7110.r480b = 0x00; |
| 881 | | snes_spc7110.r480c = 0x00; |
| 882 | | |
| 883 | | snes_spc7110.r4811 = 0x00; |
| 884 | | snes_spc7110.r4812 = 0x00; |
| 885 | | snes_spc7110.r4813 = 0x00; |
| 886 | | snes_spc7110.r4814 = 0x00; |
| 887 | | snes_spc7110.r4815 = 0x00; |
| 888 | | snes_spc7110.r4816 = 0x00; |
| 889 | | snes_spc7110.r4817 = 0x00; |
| 890 | | snes_spc7110.r4818 = 0x00; |
| 891 | | |
| 892 | | snes_spc7110.r481x = 0x00; |
| 893 | | snes_spc7110.r4814_latch = 0; |
| 894 | | snes_spc7110.r4815_latch = 0; |
| 895 | | |
| 896 | | snes_spc7110.r4820 = 0x00; |
| 897 | | snes_spc7110.r4821 = 0x00; |
| 898 | | snes_spc7110.r4822 = 0x00; |
| 899 | | snes_spc7110.r4823 = 0x00; |
| 900 | | snes_spc7110.r4824 = 0x00; |
| 901 | | snes_spc7110.r4825 = 0x00; |
| 902 | | snes_spc7110.r4826 = 0x00; |
| 903 | | snes_spc7110.r4827 = 0x00; |
| 904 | | snes_spc7110.r4828 = 0x00; |
| 905 | | snes_spc7110.r4829 = 0x00; |
| 906 | | snes_spc7110.r482a = 0x00; |
| 907 | | snes_spc7110.r482b = 0x00; |
| 908 | | snes_spc7110.r482c = 0x00; |
| 909 | | snes_spc7110.r482d = 0x00; |
| 910 | | snes_spc7110.r482e = 0x00; |
| 911 | | snes_spc7110.r482f = 0x00; |
| 912 | | |
| 913 | | snes_spc7110.r4830 = 0x00; |
| 914 | | spc7110_mmio_write(machine, 0x4831, 0); |
| 915 | | spc7110_mmio_write(machine, 0x4832, 1); |
| 916 | | spc7110_mmio_write(machine, 0x4833, 2); |
| 917 | | snes_spc7110.r4834 = 0x00; |
| 918 | | |
| 919 | | snes_spc7110.r4840 = 0x00; |
| 920 | | snes_spc7110.r4841 = 0x00; |
| 921 | | snes_spc7110.r4842 = 0x00; |
| 922 | | |
| 923 | | snes_spc7110.size = state->m_cart_size; |
| 924 | | |
| 925 | | snes_spc7110.decomp = auto_alloc(machine, SPC7110Decomp(machine, snes_spc7110.size)); |
| 926 | | } |
| 927 | | |
| 928 | | void spc7110rtc_init(running_machine& machine) |
| 929 | | { |
| 930 | | spc7110_init(machine); |
| 931 | | |
| 932 | | snes_spc7110.rtc_state = RTCS_Inactive; |
| 933 | | snes_spc7110.rtc_mode = RTCM_Linear; |
| 934 | | snes_spc7110.rtc_index = 0; |
| 935 | | |
| 936 | | snes_spc7110.rtc_offset = 0; |
| 937 | | |
| 938 | | spc7110_update_time(machine, 0); |
| 939 | | } |
| 940 | | |
| 941 | | static UINT32 spc7110_datarom_addr(UINT32 addr) |
| 942 | | { |
| 943 | | UINT32 size = snes_spc7110.size - 0x100000; |
| 944 | | while (addr >= size) |
| 945 | | { |
| 946 | | addr -= size; |
| 947 | | } |
| 948 | | return addr + 0x100000; |
| 949 | | } |
| 950 | | |
| 951 | | static UINT32 spc7110_data_pointer(void) |
| 952 | | { |
| 953 | | return snes_spc7110.r4811 + (snes_spc7110.r4812 << 8) + (snes_spc7110.r4813 << 16); |
| 954 | | } |
| 955 | | |
| 956 | | static UINT32 spc7110_data_adjust(void) |
| 957 | | { |
| 958 | | return snes_spc7110.r4814 + (snes_spc7110.r4815 << 8); |
| 959 | | } |
| 960 | | |
| 961 | | static UINT32 spc7110_data_increment(void) |
| 962 | | { |
| 963 | | return snes_spc7110.r4816 + (snes_spc7110.r4817 << 8); |
| 964 | | } |
| 965 | | |
| 966 | | static void spc7110_set_data_pointer(UINT32 addr) |
| 967 | | { |
| 968 | | snes_spc7110.r4811 = addr; |
| 969 | | snes_spc7110.r4812 = addr >> 8; |
| 970 | | snes_spc7110.r4813 = addr >> 16; |
| 971 | | } |
| 972 | | |
| 973 | | static void spc7110_set_data_adjust(UINT32 addr) |
| 974 | | { |
| 975 | | snes_spc7110.r4814 = addr; |
| 976 | | snes_spc7110.r4815 = addr >> 8; |
| 977 | | } |
| 978 | | |
| 979 | | // FIXME: SPC7110 RTC is capable of rounding/adding/zero-ing seconds, so |
| 980 | | // we should probably keep track internally of the time rather than updating |
| 981 | | // to the system time at each call with a "offset" tracking as we do now... |
| 982 | | // (and indeed current code fails to pass Tengai Makyou Zero tests) |
| 983 | | static void spc7110_update_time(running_machine &machine, UINT8 offset) |
| 984 | | { |
| 985 | | system_time curtime, *systime = &curtime; |
| 986 | | machine.current_datetime(curtime); |
| 987 | | int update = 1; |
| 988 | | |
| 989 | | snes_spc7110.rtc_offset += offset; |
| 990 | | |
| 991 | | // TEST: can we go beyond 24hrs of rounding?!? I doubt it will ever go beyond 3600, but I could be wrong... |
| 992 | | assert(snes_spc7110.rtc_offset < 86400); |
| 993 | | |
| 994 | | /* do not update if CR0 or CR2 timer disable flags are set */ |
| 995 | | if ((snes_spc7110.rtc_ram[13] & 0x01) || (snes_spc7110.rtc_ram[15] & 0x03)) |
| 996 | | update = 0; |
| 997 | | |
| 998 | | if (update) |
| 999 | | { |
| 1000 | | /* update time with offset, assuming offset < 3600s */ |
| 1001 | | UINT8 second = systime->local_time.second; |
| 1002 | | UINT8 minute = systime->local_time.minute; |
| 1003 | | UINT8 hour = systime->local_time.hour; |
| 1004 | | UINT8 mday = systime->local_time.mday; |
| 1005 | | |
| 1006 | | while (snes_spc7110.rtc_offset >= 3600) |
| 1007 | | { |
| 1008 | | snes_spc7110.rtc_offset -= 3600; |
| 1009 | | hour++; |
| 1010 | | |
| 1011 | | if (hour == 24) |
| 1012 | | { |
| 1013 | | mday++; |
| 1014 | | hour = 0; |
| 1015 | | } |
| 1016 | | } |
| 1017 | | |
| 1018 | | while (snes_spc7110.rtc_offset >= 60) |
| 1019 | | { |
| 1020 | | snes_spc7110.rtc_offset -= 60; |
| 1021 | | minute++; |
| 1022 | | |
| 1023 | | if (minute == 60) |
| 1024 | | { |
| 1025 | | hour++; |
| 1026 | | minute = 0; |
| 1027 | | } |
| 1028 | | } |
| 1029 | | |
| 1030 | | while (snes_spc7110.rtc_offset) |
| 1031 | | { |
| 1032 | | snes_spc7110.rtc_offset -= 1; |
| 1033 | | second++; |
| 1034 | | |
| 1035 | | if (second == 60) |
| 1036 | | { |
| 1037 | | minute++; |
| 1038 | | second = 0; |
| 1039 | | } |
| 1040 | | } |
| 1041 | | |
| 1042 | | snes_spc7110.rtc_ram[0] = second % 10; |
| 1043 | | snes_spc7110.rtc_ram[1] = second / 10; |
| 1044 | | snes_spc7110.rtc_ram[2] = minute % 10; |
| 1045 | | snes_spc7110.rtc_ram[3] = minute / 10; |
| 1046 | | snes_spc7110.rtc_ram[4] = hour % 10; |
| 1047 | | snes_spc7110.rtc_ram[5] = hour / 10; |
| 1048 | | snes_spc7110.rtc_ram[6] = mday % 10; |
| 1049 | | snes_spc7110.rtc_ram[7] = mday / 10; |
| 1050 | | snes_spc7110.rtc_ram[8] = systime->local_time.month % 10; |
| 1051 | | snes_spc7110.rtc_ram[9] = systime->local_time.month / 10; |
| 1052 | | snes_spc7110.rtc_ram[8] = systime->local_time.month; |
| 1053 | | snes_spc7110.rtc_ram[10] = (systime->local_time.year - 1900) % 10; |
| 1054 | | snes_spc7110.rtc_ram[11] = ((systime->local_time.year - 1900) / 10) % 10; |
| 1055 | | snes_spc7110.rtc_ram[12] = systime->local_time.weekday % 7; |
| 1056 | | } |
| 1057 | | } |
| 1058 | | |
| 1059 | | UINT8 spc7110_mmio_read(address_space &space, UINT32 addr) |
| 1060 | | { |
| 1061 | | running_machine &machine = space.machine(); |
| 1062 | | UINT8 *ROM = machine.root_device().memregion("cart")->base(); |
| 1063 | | |
| 1064 | | addr &= 0xffff; |
| 1065 | | |
| 1066 | | switch(addr) |
| 1067 | | { |
| 1068 | | //================== |
| 1069 | | //decompression unit |
| 1070 | | //================== |
| 1071 | | |
| 1072 | | case 0x4800: |
| 1073 | | { |
| 1074 | | UINT16 counter = (snes_spc7110.r4809 + (snes_spc7110.r480a << 8)); |
| 1075 | | counter--; |
| 1076 | | snes_spc7110.r4809 = counter; |
| 1077 | | snes_spc7110.r480a = counter >> 8; |
| 1078 | | return snes_spc7110.decomp->read(ROM); |
| 1079 | | } |
| 1080 | | case 0x4801: return snes_spc7110.r4801; |
| 1081 | | case 0x4802: return snes_spc7110.r4802; |
| 1082 | | case 0x4803: return snes_spc7110.r4803; |
| 1083 | | case 0x4804: return snes_spc7110.r4804; |
| 1084 | | case 0x4805: return snes_spc7110.r4805; |
| 1085 | | case 0x4806: return snes_spc7110.r4806; |
| 1086 | | case 0x4807: return snes_spc7110.r4807; |
| 1087 | | case 0x4808: return snes_spc7110.r4808; |
| 1088 | | case 0x4809: return snes_spc7110.r4809; |
| 1089 | | case 0x480a: return snes_spc7110.r480a; |
| 1090 | | case 0x480b: return snes_spc7110.r480b; |
| 1091 | | case 0x480c: |
| 1092 | | { |
| 1093 | | UINT8 status = snes_spc7110.r480c; |
| 1094 | | snes_spc7110.r480c &= 0x7f; |
| 1095 | | return status; |
| 1096 | | } |
| 1097 | | |
| 1098 | | //============== |
| 1099 | | //data port unit |
| 1100 | | //============== |
| 1101 | | |
| 1102 | | case 0x4810: |
| 1103 | | { |
| 1104 | | UINT8 data; |
| 1105 | | UINT32 address, adjust, adjustaddr; |
| 1106 | | |
| 1107 | | if (snes_spc7110.r481x != 0x07) return 0x00; |
| 1108 | | |
| 1109 | | address = spc7110_data_pointer(); |
| 1110 | | adjust = spc7110_data_adjust(); |
| 1111 | | if (snes_spc7110.r4818 & 8) |
| 1112 | | { |
| 1113 | | adjust = (INT16)adjust; //16-bit sign extend |
| 1114 | | } |
| 1115 | | |
| 1116 | | adjustaddr = address; |
| 1117 | | if (snes_spc7110.r4818 & 2) |
| 1118 | | { |
| 1119 | | adjustaddr += adjust; |
| 1120 | | spc7110_set_data_adjust(adjust + 1); |
| 1121 | | } |
| 1122 | | |
| 1123 | | data = ROM[spc7110_datarom_addr(adjustaddr)]; |
| 1124 | | if (!(snes_spc7110.r4818 & 2)) |
| 1125 | | { |
| 1126 | | UINT32 increment = (snes_spc7110.r4818 & 1) ? spc7110_data_increment() : 1; |
| 1127 | | if (snes_spc7110.r4818 & 4) |
| 1128 | | { |
| 1129 | | increment = (INT16)increment; //16-bit sign extend |
| 1130 | | } |
| 1131 | | |
| 1132 | | if ((snes_spc7110.r4818 & 16) == 0) |
| 1133 | | { |
| 1134 | | spc7110_set_data_pointer(address + increment); |
| 1135 | | } |
| 1136 | | else |
| 1137 | | { |
| 1138 | | spc7110_set_data_adjust(adjust + increment); |
| 1139 | | } |
| 1140 | | } |
| 1141 | | |
| 1142 | | return data; |
| 1143 | | } |
| 1144 | | case 0x4811: return snes_spc7110.r4811; |
| 1145 | | case 0x4812: return snes_spc7110.r4812; |
| 1146 | | case 0x4813: return snes_spc7110.r4813; |
| 1147 | | case 0x4814: return snes_spc7110.r4814; |
| 1148 | | case 0x4815: return snes_spc7110.r4815; |
| 1149 | | case 0x4816: return snes_spc7110.r4816; |
| 1150 | | case 0x4817: return snes_spc7110.r4817; |
| 1151 | | case 0x4818: return snes_spc7110.r4818; |
| 1152 | | case 0x481a: |
| 1153 | | { |
| 1154 | | UINT8 data; |
| 1155 | | UINT32 address, adjust; |
| 1156 | | if (snes_spc7110.r481x != 0x07) |
| 1157 | | { |
| 1158 | | return 0x00; |
| 1159 | | } |
| 1160 | | |
| 1161 | | address = spc7110_data_pointer(); |
| 1162 | | adjust = spc7110_data_adjust(); |
| 1163 | | if (snes_spc7110.r4818 & 8) |
| 1164 | | { |
| 1165 | | adjust = (INT16)adjust; //16-bit sign extend |
| 1166 | | } |
| 1167 | | |
| 1168 | | data = ROM[spc7110_datarom_addr(address + adjust)]; |
| 1169 | | if ((snes_spc7110.r4818 & 0x60) == 0x60) |
| 1170 | | { |
| 1171 | | if ((snes_spc7110.r4818 & 16) == 0) |
| 1172 | | { |
| 1173 | | spc7110_set_data_pointer(address + adjust); |
| 1174 | | } |
| 1175 | | else |
| 1176 | | { |
| 1177 | | spc7110_set_data_adjust(adjust + adjust); |
| 1178 | | } |
| 1179 | | } |
| 1180 | | |
| 1181 | | return data; |
| 1182 | | } |
| 1183 | | |
| 1184 | | //========= |
| 1185 | | //math unit |
| 1186 | | //========= |
| 1187 | | |
| 1188 | | case 0x4820: return snes_spc7110.r4820; |
| 1189 | | case 0x4821: return snes_spc7110.r4821; |
| 1190 | | case 0x4822: return snes_spc7110.r4822; |
| 1191 | | case 0x4823: return snes_spc7110.r4823; |
| 1192 | | case 0x4824: return snes_spc7110.r4824; |
| 1193 | | case 0x4825: return snes_spc7110.r4825; |
| 1194 | | case 0x4826: return snes_spc7110.r4826; |
| 1195 | | case 0x4827: return snes_spc7110.r4827; |
| 1196 | | case 0x4828: return snes_spc7110.r4828; |
| 1197 | | case 0x4829: return snes_spc7110.r4829; |
| 1198 | | case 0x482a: return snes_spc7110.r482a; |
| 1199 | | case 0x482b: return snes_spc7110.r482b; |
| 1200 | | case 0x482c: return snes_spc7110.r482c; |
| 1201 | | case 0x482d: return snes_spc7110.r482d; |
| 1202 | | case 0x482e: return snes_spc7110.r482e; |
| 1203 | | case 0x482f: |
| 1204 | | { |
| 1205 | | UINT8 status = snes_spc7110.r482f; |
| 1206 | | snes_spc7110.r482f &= 0x7f; |
| 1207 | | return status; |
| 1208 | | } |
| 1209 | | |
| 1210 | | //=================== |
| 1211 | | //memory mapping unit |
| 1212 | | //=================== |
| 1213 | | |
| 1214 | | case 0x4830: return snes_spc7110.r4830; |
| 1215 | | case 0x4831: return snes_spc7110.r4831; |
| 1216 | | case 0x4832: return snes_spc7110.r4832; |
| 1217 | | case 0x4833: return snes_spc7110.r4833; |
| 1218 | | case 0x4834: return snes_spc7110.r4834; |
| 1219 | | |
| 1220 | | //==================== |
| 1221 | | //real-time clock unit |
| 1222 | | //==================== |
| 1223 | | case 0x4840: return snes_spc7110.r4840; |
| 1224 | | case 0x4841: |
| 1225 | | { |
| 1226 | | UINT8 data = 0; |
| 1227 | | if (snes_spc7110.rtc_state == RTCS_Inactive || snes_spc7110.rtc_state == RTCS_ModeSelect) |
| 1228 | | return 0x00; |
| 1229 | | |
| 1230 | | snes_spc7110.r4842 = 0x80; |
| 1231 | | data = snes_spc7110.rtc_ram[snes_spc7110.rtc_index]; |
| 1232 | | snes_spc7110.rtc_index = (snes_spc7110.rtc_index + 1) & 15; |
| 1233 | | return data; |
| 1234 | | } |
| 1235 | | case 0x4842: |
| 1236 | | { |
| 1237 | | UINT8 status = snes_spc7110.r4842; |
| 1238 | | snes_spc7110.r4842 &= 0x7f; |
| 1239 | | return status; |
| 1240 | | } |
| 1241 | | } |
| 1242 | | |
| 1243 | | return snes_open_bus_r(space, 0); |
| 1244 | | } |
| 1245 | | |
| 1246 | | void spc7110_mmio_write(running_machine &machine, UINT32 addr, UINT8 data) |
| 1247 | | { |
| 1248 | | UINT8 *ROM = machine.root_device().memregion("cart")->base(); |
| 1249 | | |
| 1250 | | addr &= 0xffff; |
| 1251 | | |
| 1252 | | switch(addr) |
| 1253 | | { |
| 1254 | | //================== |
| 1255 | | //decompression unit |
| 1256 | | //================== |
| 1257 | | |
| 1258 | | case 0x4801: snes_spc7110.r4801 = data; break; |
| 1259 | | case 0x4802: snes_spc7110.r4802 = data; break; |
| 1260 | | case 0x4803: snes_spc7110.r4803 = data; break; |
| 1261 | | case 0x4804: snes_spc7110.r4804 = data; break; |
| 1262 | | case 0x4805: snes_spc7110.r4805 = data; break; |
| 1263 | | case 0x4806: |
| 1264 | | { |
| 1265 | | UINT32 table, index, address, mode, offset; |
| 1266 | | snes_spc7110.r4806 = data; |
| 1267 | | |
| 1268 | | table = (snes_spc7110.r4801 + (snes_spc7110.r4802 << 8) + (snes_spc7110.r4803 << 16)); |
| 1269 | | index = (snes_spc7110.r4804 << 2); |
| 1270 | | //length = (snes_spc7110.r4809 + (snes_spc7110.r480a << 8)); |
| 1271 | | address = spc7110_datarom_addr(table + index); |
| 1272 | | mode = (ROM[address + 0]); |
| 1273 | | offset = (ROM[address + 1] << 16) |
| 1274 | | + (ROM[address + 2] << 8) |
| 1275 | | + (ROM[address + 3] << 0); |
| 1276 | | |
| 1277 | | snes_spc7110.decomp->init(machine, ROM, mode, offset, (snes_spc7110.r4805 + (snes_spc7110.r4806 << 8)) << mode); |
| 1278 | | snes_spc7110.r480c = 0x80; |
| 1279 | | } |
| 1280 | | break; |
| 1281 | | |
| 1282 | | case 0x4807: snes_spc7110.r4807 = data; break; |
| 1283 | | case 0x4808: snes_spc7110.r4808 = data; break; |
| 1284 | | case 0x4809: snes_spc7110.r4809 = data; break; |
| 1285 | | case 0x480a: snes_spc7110.r480a = data; break; |
| 1286 | | case 0x480b: snes_spc7110.r480b = data; break; |
| 1287 | | |
| 1288 | | //============== |
| 1289 | | //data port unit |
| 1290 | | //============== |
| 1291 | | |
| 1292 | | case 0x4811: snes_spc7110.r4811 = data; snes_spc7110.r481x |= 0x01; break; |
| 1293 | | case 0x4812: snes_spc7110.r4812 = data; snes_spc7110.r481x |= 0x02; break; |
| 1294 | | case 0x4813: snes_spc7110.r4813 = data; snes_spc7110.r481x |= 0x04; break; |
| 1295 | | case 0x4814: |
| 1296 | | { |
| 1297 | | snes_spc7110.r4814 = data; |
| 1298 | | snes_spc7110.r4814_latch = 1; |
| 1299 | | if (!snes_spc7110.r4815_latch) |
| 1300 | | { |
| 1301 | | break; |
| 1302 | | } |
| 1303 | | if (!(snes_spc7110.r4818 & 2)) |
| 1304 | | { |
| 1305 | | break; |
| 1306 | | } |
| 1307 | | if (snes_spc7110.r4818 & 0x10) |
| 1308 | | { |
| 1309 | | break; |
| 1310 | | } |
| 1311 | | |
| 1312 | | if ((snes_spc7110.r4818 & 0x60) == 0x20) |
| 1313 | | { |
| 1314 | | UINT32 increment = spc7110_data_adjust() & 0xff; |
| 1315 | | if (snes_spc7110.r4818 & 8) |
| 1316 | | { |
| 1317 | | increment = (INT8)increment; //8-bit sign extend |
| 1318 | | } |
| 1319 | | spc7110_set_data_pointer(spc7110_data_pointer() + increment); |
| 1320 | | } |
| 1321 | | else if ((snes_spc7110.r4818 & 0x60) == 0x40) |
| 1322 | | { |
| 1323 | | UINT32 increment = spc7110_data_adjust(); |
| 1324 | | if (snes_spc7110.r4818 & 8) |
| 1325 | | { |
| 1326 | | increment = (INT16)increment; //16-bit sign extend |
| 1327 | | } |
| 1328 | | spc7110_set_data_pointer(spc7110_data_pointer() + increment); |
| 1329 | | } |
| 1330 | | break; |
| 1331 | | } |
| 1332 | | |
| 1333 | | case 0x4815: |
| 1334 | | { |
| 1335 | | snes_spc7110.r4815 = data; |
| 1336 | | snes_spc7110.r4815_latch = 1; |
| 1337 | | if (!snes_spc7110.r4814_latch) |
| 1338 | | { |
| 1339 | | break; |
| 1340 | | } |
| 1341 | | if (!(snes_spc7110.r4818 & 2)) |
| 1342 | | { |
| 1343 | | break; |
| 1344 | | } |
| 1345 | | if (snes_spc7110.r4818 & 0x10) |
| 1346 | | { |
| 1347 | | break; |
| 1348 | | } |
| 1349 | | |
| 1350 | | if ((snes_spc7110.r4818 & 0x60) == 0x20) |
| 1351 | | { |
| 1352 | | UINT32 increment = spc7110_data_adjust() & 0xff; |
| 1353 | | if (snes_spc7110.r4818 & 8) |
| 1354 | | { |
| 1355 | | increment = (INT8)increment; //8-bit sign extend |
| 1356 | | } |
| 1357 | | spc7110_set_data_pointer(spc7110_data_pointer() + increment); |
| 1358 | | } |
| 1359 | | else if ((snes_spc7110.r4818 & 0x60) == 0x40) |
| 1360 | | { |
| 1361 | | UINT32 increment = spc7110_data_adjust(); |
| 1362 | | if (snes_spc7110.r4818 & 8) |
| 1363 | | { |
| 1364 | | increment = (INT16)increment; //16-bit sign extend |
| 1365 | | } |
| 1366 | | spc7110_set_data_pointer(spc7110_data_pointer() + increment); |
| 1367 | | } |
| 1368 | | break; |
| 1369 | | } |
| 1370 | | |
| 1371 | | case 0x4816: snes_spc7110.r4816 = data; break; |
| 1372 | | case 0x4817: snes_spc7110.r4817 = data; break; |
| 1373 | | case 0x4818: |
| 1374 | | { |
| 1375 | | if (snes_spc7110.r481x != 0x07) |
| 1376 | | break; |
| 1377 | | |
| 1378 | | snes_spc7110.r4818 = data; |
| 1379 | | snes_spc7110.r4814_latch = snes_spc7110.r4815_latch = 0; |
| 1380 | | break; |
| 1381 | | } |
| 1382 | | |
| 1383 | | //========= |
| 1384 | | //math unit |
| 1385 | | //========= |
| 1386 | | |
| 1387 | | case 0x4820: snes_spc7110.r4820 = data; break; |
| 1388 | | case 0x4821: snes_spc7110.r4821 = data; break; |
| 1389 | | case 0x4822: snes_spc7110.r4822 = data; break; |
| 1390 | | case 0x4823: snes_spc7110.r4823 = data; break; |
| 1391 | | case 0x4824: snes_spc7110.r4824 = data; break; |
| 1392 | | case 0x4825: |
| 1393 | | { |
| 1394 | | snes_spc7110.r4825 = data; |
| 1395 | | |
| 1396 | | if (snes_spc7110.r482e & 1) |
| 1397 | | { |
| 1398 | | //signed 16-bit x 16-bit multiplication |
| 1399 | | INT16 r0 = (INT16)(snes_spc7110.r4824 + (snes_spc7110.r4825 << 8)); |
| 1400 | | INT16 r1 = (INT16)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8)); |
| 1401 | | |
| 1402 | | INT32 result = r0 * r1; |
| 1403 | | snes_spc7110.r4828 = result; |
| 1404 | | snes_spc7110.r4829 = result >> 8; |
| 1405 | | snes_spc7110.r482a = result >> 16; |
| 1406 | | snes_spc7110.r482b = result >> 24; |
| 1407 | | } |
| 1408 | | else |
| 1409 | | { |
| 1410 | | //unsigned 16-bit x 16-bit multiplication |
| 1411 | | UINT16 r0 = (UINT16)(snes_spc7110.r4824 + (snes_spc7110.r4825 << 8)); |
| 1412 | | UINT16 r1 = (UINT16)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8)); |
| 1413 | | |
| 1414 | | UINT32 result = r0 * r1; |
| 1415 | | snes_spc7110.r4828 = result; |
| 1416 | | snes_spc7110.r4829 = result >> 8; |
| 1417 | | snes_spc7110.r482a = result >> 16; |
| 1418 | | snes_spc7110.r482b = result >> 24; |
| 1419 | | } |
| 1420 | | |
| 1421 | | snes_spc7110.r482f = 0x80; |
| 1422 | | break; |
| 1423 | | } |
| 1424 | | |
| 1425 | | case 0x4826: snes_spc7110.r4826 = data; break; |
| 1426 | | case 0x4827: |
| 1427 | | { |
| 1428 | | snes_spc7110.r4827 = data; |
| 1429 | | |
| 1430 | | if (snes_spc7110.r482e & 1) |
| 1431 | | { |
| 1432 | | //signed 32-bit x 16-bit division |
| 1433 | | INT32 dividend = (INT32)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8) + (snes_spc7110.r4822 << 16) + (snes_spc7110.r4823 << 24)); |
| 1434 | | INT16 divisor = (INT16)(snes_spc7110.r4826 + (snes_spc7110.r4827 << 8)); |
| 1435 | | |
| 1436 | | INT32 quotient; |
| 1437 | | INT16 remainder; |
| 1438 | | |
| 1439 | | if (divisor) |
| 1440 | | { |
| 1441 | | quotient = (INT32)(dividend / divisor); |
| 1442 | | remainder = (INT32)(dividend % divisor); |
| 1443 | | } |
| 1444 | | else |
| 1445 | | { |
| 1446 | | //illegal division by zero |
| 1447 | | quotient = 0; |
| 1448 | | remainder = dividend & 0xffff; |
| 1449 | | } |
| 1450 | | |
| 1451 | | snes_spc7110.r4828 = quotient; |
| 1452 | | snes_spc7110.r4829 = quotient >> 8; |
| 1453 | | snes_spc7110.r482a = quotient >> 16; |
| 1454 | | snes_spc7110.r482b = quotient >> 24; |
| 1455 | | |
| 1456 | | snes_spc7110.r482c = remainder; |
| 1457 | | snes_spc7110.r482d = remainder >> 8; |
| 1458 | | } |
| 1459 | | else |
| 1460 | | { |
| 1461 | | //unsigned 32-bit x 16-bit division |
| 1462 | | UINT32 dividend = (UINT32)(snes_spc7110.r4820 + (snes_spc7110.r4821 << 8) + (snes_spc7110.r4822 << 16) + (snes_spc7110.r4823 << 24)); |
| 1463 | | UINT16 divisor = (UINT16)(snes_spc7110.r4826 + (snes_spc7110.r4827 << 8)); |
| 1464 | | |
| 1465 | | UINT32 quotient; |
| 1466 | | UINT16 remainder; |
| 1467 | | |
| 1468 | | if (divisor) |
| 1469 | | { |
| 1470 | | quotient = (UINT32)(dividend / divisor); |
| 1471 | | remainder = (UINT16)(dividend % divisor); |
| 1472 | | } |
| 1473 | | else |
| 1474 | | { |
| 1475 | | //illegal division by zero |
| 1476 | | quotient = 0; |
| 1477 | | remainder = dividend & 0xffff; |
| 1478 | | } |
| 1479 | | |
| 1480 | | snes_spc7110.r4828 = quotient; |
| 1481 | | snes_spc7110.r4829 = quotient >> 8; |
| 1482 | | snes_spc7110.r482a = quotient >> 16; |
| 1483 | | snes_spc7110.r482b = quotient >> 24; |
| 1484 | | |
| 1485 | | snes_spc7110.r482c = remainder; |
| 1486 | | snes_spc7110.r482d = remainder >> 8; |
| 1487 | | } |
| 1488 | | |
| 1489 | | snes_spc7110.r482f = 0x80; |
| 1490 | | break; |
| 1491 | | } |
| 1492 | | |
| 1493 | | case 0x482e: |
| 1494 | | { |
| 1495 | | //reset math unit |
| 1496 | | snes_spc7110.r4820 = snes_spc7110.r4821 = snes_spc7110.r4822 = snes_spc7110.r4823 = 0; |
| 1497 | | snes_spc7110.r4824 = snes_spc7110.r4825 = snes_spc7110.r4826 = snes_spc7110.r4827 = 0; |
| 1498 | | snes_spc7110.r4828 = snes_spc7110.r4829 = snes_spc7110.r482a = snes_spc7110.r482b = 0; |
| 1499 | | snes_spc7110.r482c = snes_spc7110.r482d = 0; |
| 1500 | | |
| 1501 | | snes_spc7110.r482e = data; |
| 1502 | | break; |
| 1503 | | } |
| 1504 | | |
| 1505 | | //=================== |
| 1506 | | //memory mapping unit |
| 1507 | | //=================== |
| 1508 | | |
| 1509 | | case 0x4830: snes_spc7110.r4830 = data; break; |
| 1510 | | |
| 1511 | | case 0x4831: |
| 1512 | | { |
| 1513 | | snes_spc7110.r4831 = data; |
| 1514 | | snes_spc7110.dx_offset = spc7110_datarom_addr(data * 0x100000); |
| 1515 | | break; |
| 1516 | | } |
| 1517 | | |
| 1518 | | case 0x4832: |
| 1519 | | { |
| 1520 | | snes_spc7110.r4832 = data; |
| 1521 | | snes_spc7110.ex_offset = spc7110_datarom_addr(data * 0x100000); |
| 1522 | | break; |
| 1523 | | } |
| 1524 | | |
| 1525 | | case 0x4833: |
| 1526 | | { |
| 1527 | | snes_spc7110.r4833 = data; |
| 1528 | | snes_spc7110.fx_offset = spc7110_datarom_addr(data * 0x100000); |
| 1529 | | break; |
| 1530 | | } |
| 1531 | | |
| 1532 | | case 0x4834: snes_spc7110.r4834 = data; break; |
| 1533 | | |
| 1534 | | //==================== |
| 1535 | | //real-time clock unit |
| 1536 | | //==================== |
| 1537 | | |
| 1538 | | case 0x4840: |
| 1539 | | { |
| 1540 | | snes_spc7110.r4840 = data; |
| 1541 | | |
| 1542 | | if (!(snes_spc7110.r4840 & 1)) |
| 1543 | | { |
| 1544 | | //disable RTC |
| 1545 | | snes_spc7110.rtc_state = RTCS_Inactive; |
| 1546 | | spc7110_update_time(machine, 0); |
| 1547 | | } |
| 1548 | | else |
| 1549 | | { |
| 1550 | | //enable RTC |
| 1551 | | snes_spc7110.r4842 = 0x80; |
| 1552 | | snes_spc7110.rtc_state = RTCS_ModeSelect; |
| 1553 | | } |
| 1554 | | } |
| 1555 | | break; |
| 1556 | | |
| 1557 | | case 0x4841: |
| 1558 | | { |
| 1559 | | snes_spc7110.r4841 = data; |
| 1560 | | |
| 1561 | | switch (snes_spc7110.rtc_state) |
| 1562 | | { |
| 1563 | | case RTCS_ModeSelect: |
| 1564 | | if (data == RTCM_Linear || data == RTCM_Indexed) |
| 1565 | | { |
| 1566 | | snes_spc7110.r4842 = 0x80; |
| 1567 | | snes_spc7110.rtc_state = RTCS_IndexSelect; |
| 1568 | | snes_spc7110.rtc_mode = (RTC_Mode)data; |
| 1569 | | snes_spc7110.rtc_index = 0; |
| 1570 | | } |
| 1571 | | break; |
| 1572 | | |
| 1573 | | case RTCS_IndexSelect: |
| 1574 | | snes_spc7110.r4842 = 0x80; |
| 1575 | | snes_spc7110.rtc_index = data & 15; |
| 1576 | | if (snes_spc7110.rtc_mode == RTCM_Linear) |
| 1577 | | snes_spc7110.rtc_state = RTCS_Write; |
| 1578 | | break; |
| 1579 | | |
| 1580 | | case RTCS_Write: |
| 1581 | | snes_spc7110.r4842 = 0x80; |
| 1582 | | |
| 1583 | | //control register 0 |
| 1584 | | if (snes_spc7110.rtc_index == 13) |
| 1585 | | { |
| 1586 | | //increment second counter |
| 1587 | | if (data & 2) |
| 1588 | | spc7110_update_time(machine, 1); |
| 1589 | | |
| 1590 | | //round minute counter |
| 1591 | | if (data & 8) |
| 1592 | | { |
| 1593 | | spc7110_update_time(machine, 0); |
| 1594 | | |
| 1595 | | UINT8 second = snes_spc7110.rtc_ram[0] + snes_spc7110.rtc_ram[1] * 10; |
| 1596 | | //clear seconds |
| 1597 | | snes_spc7110.rtc_ram[0] = 0; |
| 1598 | | snes_spc7110.rtc_ram[1] = 0; |
| 1599 | | |
| 1600 | | if (second >= 30) |
| 1601 | | spc7110_update_time(machine, 60); |
| 1602 | | } |
| 1603 | | } |
| 1604 | | |
| 1605 | | //control register 2 |
| 1606 | | if (snes_spc7110.rtc_index == 15) |
| 1607 | | { |
| 1608 | | //disable timer and clear second counter |
| 1609 | | if ((data & 1) && !(snes_spc7110.rtc_ram[15] & 1)) |
| 1610 | | { |
| 1611 | | spc7110_update_time(machine, 0); |
| 1612 | | |
| 1613 | | //clear seconds |
| 1614 | | snes_spc7110.rtc_ram[0] = 0; |
| 1615 | | snes_spc7110.rtc_ram[1] = 0; |
| 1616 | | } |
| 1617 | | |
| 1618 | | //disable timer |
| 1619 | | if ((data & 2) && !(snes_spc7110.rtc_ram[15] & 2)) |
| 1620 | | spc7110_update_time(machine, 0); |
| 1621 | | } |
| 1622 | | |
| 1623 | | snes_spc7110.rtc_ram[snes_spc7110.rtc_index] = data & 15; |
| 1624 | | snes_spc7110.rtc_index = (snes_spc7110.rtc_index + 1) & 15; |
| 1625 | | break; |
| 1626 | | } |
| 1627 | | } |
| 1628 | | break; |
| 1629 | | } |
| 1630 | | } |
| 1631 | | |
| 1632 | | UINT8 spc7110_bank7_read(address_space &space, UINT32 offset) |
| 1633 | | { |
| 1634 | | UINT8 *ROM = space.machine().root_device().memregion("cart")->base(); |
| 1635 | | UINT32 addr = offset & 0x0fffff; |
| 1636 | | |
| 1637 | | switch (offset & 0xf00000) |
| 1638 | | { |
| 1639 | | case 0x100000: |
| 1640 | | return ROM[snes_spc7110.dx_offset + addr]; |
| 1641 | | case 0x200000: |
| 1642 | | return ROM[snes_spc7110.ex_offset + addr]; |
| 1643 | | case 0x300000: |
| 1644 | | return ROM[snes_spc7110.fx_offset + addr]; |
| 1645 | | default: |
| 1646 | | break; |
| 1647 | | } |
| 1648 | | return snes_open_bus_r(space, 0); |
| 1649 | | } |