src/mame/machine/dccons.c
| r11529 | r11530 | |
| 1 | | /* |
| 2 | | |
| 3 | | dc.c - Sega Dreamcast hardware |
| 4 | | |
| 5 | | MESS (DC home console) hardware overrides (GD-ROM drive etc) |
| 6 | | |
| 7 | | c230048 - 5 is written, want 6 |
| 8 | | c0d9d9e - where bad happens, from routine @ c0da260 |
| 9 | | |
| 10 | | c0d9d8e - R0 on return is the value to put in |
| 11 | | |
| 12 | | cfffee0 - stack location when bad happens |
| 13 | | |
| 14 | | */ |
| 15 | | |
| 16 | | #include "emu.h" |
| 17 | | #include "cdrom.h" |
| 18 | | #include "debugger.h" |
| 19 | | #include "includes/dc.h" |
| 20 | | #include "cpu/sh4/sh4.h" |
| 21 | | #include "sound/aica.h" |
| 22 | | #include "includes/naomi.h" |
| 23 | | #include "machine/gdrom.h" |
| 24 | | #include "imagedev/chd_cd.h" |
| 25 | | |
| 26 | | #define ATAPI_CYCLES_PER_SECTOR (5000) // TBD for Dreamcast |
| 27 | | |
| 28 | | #define ATAPI_STAT_BSY 0x80 |
| 29 | | #define ATAPI_STAT_DRDY 0x40 |
| 30 | | #define ATAPI_STAT_DMARDDF 0x20 |
| 31 | | #define ATAPI_STAT_SERVDSC 0x10 |
| 32 | | #define ATAPI_STAT_DRQ 0x08 |
| 33 | | #define ATAPI_STAT_CORR 0x04 |
| 34 | | #define ATAPI_STAT_CHECK 0x01 |
| 35 | | |
| 36 | | #define ATAPI_INTREASON_COMMAND 0x01 |
| 37 | | #define ATAPI_INTREASON_IO 0x02 |
| 38 | | #define ATAPI_INTREASON_RELEASE 0x04 |
| 39 | | |
| 40 | | #define ATAPI_REG_DATA 0 |
| 41 | | #define ATAPI_REG_FEATURES 1 |
| 42 | | #define ATAPI_REG_INTREASON 2 |
| 43 | | #define ATAPI_REG_SAMTAG 3 |
| 44 | | #define ATAPI_REG_COUNTLOW 4 |
| 45 | | #define ATAPI_REG_COUNTHIGH 5 |
| 46 | | #define ATAPI_REG_DRIVESEL 6 |
| 47 | | #define ATAPI_REG_CMDSTATUS 7 |
| 48 | | #define ATAPI_REG_ERROR 16 // read-only ERROR (write is FEATURES) |
| 49 | | |
| 50 | | #define ATAPI_REG_MAX 24 |
| 51 | | |
| 52 | | #define ATAPI_XFER_PIO 0x00 |
| 53 | | #define ATAPI_XFER_PIO_FLOW 0x08 |
| 54 | | #define ATAPI_XFER_MULTI_DMA 0x20 |
| 55 | | #define ATAPI_XFER_ULTRA_DMA 0x40 |
| 56 | | |
| 57 | | #define ATAPI_DATA_SIZE ( 64 * 1024 ) |
| 58 | | |
| 59 | | static UINT8 *atapi_regs; |
| 60 | | static emu_timer *atapi_timer; |
| 61 | | static SCSIInstance *gdrom_device; |
| 62 | | static UINT8 *atapi_data; |
| 63 | | static int atapi_data_ptr, atapi_data_len, atapi_xferlen, atapi_xferbase, atapi_cdata_wait, atapi_xfermod; |
| 64 | | static UINT32 gdrom_alt_status; |
| 65 | | static UINT8 xfer_mode = ATAPI_XFER_PIO; |
| 66 | | |
| 67 | | #define MAX_TRANSFER_SIZE ( 63488 ) |
| 68 | | |
| 69 | | extern UINT32 dc_sysctrl_regs[0x200/4]; |
| 70 | | |
| 71 | | extern UINT32 g1bus_regs[0x100/4]; |
| 72 | | |
| 73 | | static void gdrom_raise_irq(running_machine &machine) |
| 74 | | { |
| 75 | | dc_sysctrl_regs[SB_ISTEXT] |= IST_EXT_GDROM; |
| 76 | | dc_update_interrupt_status(machine); |
| 77 | | } |
| 78 | | |
| 79 | | static TIMER_CALLBACK( atapi_xfer_end ) |
| 80 | | { |
| 81 | | UINT8 sector_buffer[ 4096 ]; |
| 82 | | |
| 83 | | atapi_timer->adjust(attotime::never); |
| 84 | | |
| 85 | | printf("atapi_xfer_end atapi_xferlen = %d, atapi_xfermod=%d\n", atapi_xfermod, atapi_xferlen ); |
| 86 | | |
| 87 | | mame_printf_debug("ATAPI: xfer_end. xferlen = %d, atapi_xfermod = %d\n", atapi_xferlen, atapi_xfermod); |
| 88 | | |
| 89 | | while (atapi_xferlen > 0 ) |
| 90 | | { |
| 91 | | struct sh4_ddt_dma ddtdata; |
| 92 | | |
| 93 | | // get a sector from the SCSI device |
| 94 | | SCSIReadData( gdrom_device, sector_buffer, 2048 ); |
| 95 | | |
| 96 | | atapi_xferlen -= 2048; |
| 97 | | |
| 98 | | // perform the DMA |
| 99 | | ddtdata.destination = atapi_xferbase; // destination address |
| 100 | | ddtdata.length = 2048/4; |
| 101 | | ddtdata.size = 4; |
| 102 | | ddtdata.buffer = sector_buffer; |
| 103 | | ddtdata.direction=1; // 0 source to buffer, 1 buffer to destination |
| 104 | | ddtdata.channel= -1; // not used |
| 105 | | ddtdata.mode= -1; // copy from/to buffer |
| 106 | | printf("ATAPI: DMA one sector to %x, %x remaining\n", atapi_xferbase, atapi_xferlen); |
| 107 | | sh4_dma_ddt(machine.device("maincpu"), &ddtdata); |
| 108 | | |
| 109 | | atapi_xferbase += 2048; |
| 110 | | } |
| 111 | | |
| 112 | | if (atapi_xfermod > MAX_TRANSFER_SIZE) |
| 113 | | { |
| 114 | | atapi_xferlen = MAX_TRANSFER_SIZE; |
| 115 | | atapi_xfermod = atapi_xfermod - MAX_TRANSFER_SIZE; |
| 116 | | } |
| 117 | | else |
| 118 | | { |
| 119 | | atapi_xferlen = atapi_xfermod; |
| 120 | | atapi_xfermod = 0; |
| 121 | | } |
| 122 | | |
| 123 | | if (atapi_xferlen > 0) |
| 124 | | { |
| 125 | | printf("ATAPI: starting next piece of multi-part transfer\n"); |
| 126 | | atapi_regs[ATAPI_REG_COUNTLOW] = atapi_xferlen & 0xff; |
| 127 | | atapi_regs[ATAPI_REG_COUNTHIGH] = (atapi_xferlen>>8)&0xff; |
| 128 | | |
| 129 | | atapi_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime((ATAPI_CYCLES_PER_SECTOR * (atapi_xferlen/2048)))); |
| 130 | | } |
| 131 | | else |
| 132 | | { |
| 133 | | printf("ATAPI: Transfer completed, dropping DRQ\n"); |
| 134 | | atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRDY; |
| 135 | | gdrom_alt_status = ATAPI_STAT_DRDY; |
| 136 | | atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO | ATAPI_INTREASON_COMMAND; |
| 137 | | |
| 138 | | g1bus_regs[SB_GDST]=0; |
| 139 | | dc_sysctrl_regs[SB_ISTNRM] |= IST_DMA_GDROM; |
| 140 | | dc_update_interrupt_status(machine); |
| 141 | | } |
| 142 | | |
| 143 | | gdrom_raise_irq(machine); |
| 144 | | |
| 145 | | printf( "atapi_xfer_end: %d %d\n", atapi_xferlen, atapi_xfermod ); |
| 146 | | } |
| 147 | | |
| 148 | | static READ32_HANDLER( atapi_r ) |
| 149 | | { |
| 150 | | running_machine &machine = space->machine(); |
| 151 | | int reg, data; |
| 152 | | |
| 153 | | if (mem_mask == 0x0000ffff) // word-wide command read |
| 154 | | { |
| 155 | | // mame_printf_debug("ATAPI: packet read = %04x\n", atapi_data[atapi_data_ptr]); |
| 156 | | |
| 157 | | // assert IRQ and drop DRQ |
| 158 | | if (atapi_data_ptr == 0 && atapi_data_len == 0) |
| 159 | | { |
| 160 | | // get the data from the device |
| 161 | | if( atapi_xferlen > 0 ) |
| 162 | | { |
| 163 | | SCSIReadData( gdrom_device, atapi_data, atapi_xferlen ); |
| 164 | | atapi_data_len = atapi_xferlen; |
| 165 | | } |
| 166 | | |
| 167 | | if (atapi_xfermod > MAX_TRANSFER_SIZE) |
| 168 | | { |
| 169 | | atapi_xferlen = MAX_TRANSFER_SIZE; |
| 170 | | atapi_xfermod = atapi_xfermod - MAX_TRANSFER_SIZE; |
| 171 | | } |
| 172 | | else |
| 173 | | { |
| 174 | | atapi_xferlen = atapi_xfermod; |
| 175 | | atapi_xfermod = 0; |
| 176 | | } |
| 177 | | |
| 178 | | // printf( "atapi_r: atapi_xferlen=%d\n", atapi_xferlen ); |
| 179 | | if( atapi_xferlen != 0 ) |
| 180 | | { |
| 181 | | atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_SERVDSC; |
| 182 | | gdrom_alt_status = ATAPI_STAT_DRQ | ATAPI_STAT_SERVDSC; |
| 183 | | atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO; |
| 184 | | } |
| 185 | | else |
| 186 | | { |
| 187 | | //mame_printf_debug("ATAPI: dropping DRQ\n"); |
| 188 | | atapi_regs[ATAPI_REG_CMDSTATUS] = 0; |
| 189 | | gdrom_alt_status = 0; |
| 190 | | atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO; |
| 191 | | } |
| 192 | | |
| 193 | | atapi_regs[ATAPI_REG_COUNTLOW] = atapi_xferlen & 0xff; |
| 194 | | atapi_regs[ATAPI_REG_COUNTHIGH] = (atapi_xferlen>>8)&0xff; |
| 195 | | |
| 196 | | gdrom_raise_irq(machine); |
| 197 | | } |
| 198 | | |
| 199 | | if( atapi_data_ptr < atapi_data_len ) |
| 200 | | { |
| 201 | | data = atapi_data[atapi_data_ptr++]; |
| 202 | | data |= ( atapi_data[atapi_data_ptr++] << 8 ); |
| 203 | | if( atapi_data_ptr >= atapi_data_len ) |
| 204 | | { |
| 205 | | // printf( "atapi_r: read all bytes\n" ); |
| 206 | | atapi_data_ptr = 0; |
| 207 | | atapi_data_len = 0; |
| 208 | | |
| 209 | | if( atapi_xferlen == 0 ) |
| 210 | | { |
| 211 | | atapi_regs[ATAPI_REG_CMDSTATUS] = 0; |
| 212 | | gdrom_alt_status = 0; |
| 213 | | atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO; |
| 214 | | gdrom_raise_irq(machine); |
| 215 | | } |
| 216 | | } |
| 217 | | } |
| 218 | | else |
| 219 | | { |
| 220 | | data = 0; |
| 221 | | } |
| 222 | | } |
| 223 | | else |
| 224 | | { |
| 225 | | reg = offset; |
| 226 | | |
| 227 | | // get read-only side of read-only/write-only registers from elsewhere |
| 228 | | if (reg == ATAPI_REG_FEATURES) |
| 229 | | { |
| 230 | | reg = ATAPI_REG_ERROR; |
| 231 | | } |
| 232 | | data = atapi_regs[reg]; |
| 233 | | |
| 234 | | #if 0 |
| 235 | | switch( reg ) |
| 236 | | { |
| 237 | | case ATAPI_REG_DATA: |
| 238 | | printf( "atapi_r: data=%02x\n", data ); |
| 239 | | break; |
| 240 | | case ATAPI_REG_ERROR: |
| 241 | | printf( "atapi_r: error=%02x\n", data ); |
| 242 | | break; |
| 243 | | case ATAPI_REG_INTREASON: |
| 244 | | printf( "atapi_r: intreason=%02x\n", data ); |
| 245 | | break; |
| 246 | | case ATAPI_REG_SAMTAG: |
| 247 | | printf( "atapi_r: samtag=%02x\n", data ); |
| 248 | | break; |
| 249 | | case ATAPI_REG_COUNTLOW: |
| 250 | | printf( "atapi_r: countlow=%02x\n", data ); |
| 251 | | break; |
| 252 | | case ATAPI_REG_COUNTHIGH: |
| 253 | | printf( "atapi_r: counthigh=%02x\n", data ); |
| 254 | | break; |
| 255 | | case ATAPI_REG_DRIVESEL: |
| 256 | | printf( "atapi_r: drivesel=%02x\n", data ); |
| 257 | | break; |
| 258 | | case ATAPI_REG_CMDSTATUS: |
| 259 | | printf( "atapi_r: cmdstatus=%02x\n", data ); |
| 260 | | break; |
| 261 | | } |
| 262 | | #endif |
| 263 | | |
| 264 | | mame_printf_debug("ATAPI: read reg %d = %x (PC=%x)\n", reg, data, cpu_get_pc(&space->device())); |
| 265 | | } |
| 266 | | |
| 267 | | // printf( "atapi_r( %08x, %08x ) %08x\n", offset, mem_mask, data ); |
| 268 | | return data; |
| 269 | | } |
| 270 | | |
| 271 | | static WRITE32_HANDLER( atapi_w ) |
| 272 | | { |
| 273 | | running_machine &machine = space->machine(); |
| 274 | | int reg; |
| 275 | | |
| 276 | | // printf( "atapi_w( %08x, %08x, %08x )\n", offset, mem_mask, data ); |
| 277 | | |
| 278 | | if (mem_mask == 0x0000ffff) // word-wide command write |
| 279 | | { |
| 280 | | // printf("atapi_w: data=%04x\n", data ); |
| 281 | | |
| 282 | | // printf("ATAPI: packet write %04x\n", data); |
| 283 | | atapi_data[atapi_data_ptr++] = data & 0xff; |
| 284 | | atapi_data[atapi_data_ptr++] = data >> 8; |
| 285 | | |
| 286 | | if (atapi_cdata_wait) |
| 287 | | { |
| 288 | | // printf("ATAPI: waiting, ptr %d wait %d\n", atapi_data_ptr, atapi_cdata_wait); |
| 289 | | if (atapi_data_ptr == atapi_cdata_wait) |
| 290 | | { |
| 291 | | // send it to the device |
| 292 | | SCSIWriteData( gdrom_device, atapi_data, atapi_cdata_wait ); |
| 293 | | |
| 294 | | // assert IRQ |
| 295 | | gdrom_raise_irq(machine); |
| 296 | | |
| 297 | | // not sure here, but clear DRQ at least? |
| 298 | | atapi_regs[ATAPI_REG_CMDSTATUS] = 0; |
| 299 | | } |
| 300 | | } |
| 301 | | |
| 302 | | else if ( atapi_data_ptr == 12 ) |
| 303 | | { |
| 304 | | int phase; |
| 305 | | |
| 306 | | // printf("atapi_w: command %02x\n", atapi_data[0]&0xff ); |
| 307 | | |
| 308 | | // reset data pointer for reading SCSI results |
| 309 | | atapi_data_ptr = 0; |
| 310 | | atapi_data_len = 0; |
| 311 | | |
| 312 | | // send it to the SCSI device |
| 313 | | SCSISetCommand( gdrom_device, atapi_data, 12 ); |
| 314 | | SCSIExecCommand( gdrom_device, &atapi_xferlen ); |
| 315 | | SCSIGetPhase( gdrom_device, &phase ); |
| 316 | | |
| 317 | | if (atapi_xferlen != -1) |
| 318 | | { |
| 319 | | printf("ATAPI: SCSI command %02x returned %d bytes from the device\n", atapi_data[0]&0xff, atapi_xferlen); |
| 320 | | |
| 321 | | // store the returned command length in the ATAPI regs, splitting into |
| 322 | | // multiple transfers if necessary |
| 323 | | atapi_xfermod = 0; |
| 324 | | if (atapi_xferlen > MAX_TRANSFER_SIZE) |
| 325 | | { |
| 326 | | atapi_xfermod = atapi_xferlen - MAX_TRANSFER_SIZE; |
| 327 | | atapi_xferlen = MAX_TRANSFER_SIZE; |
| 328 | | } |
| 329 | | |
| 330 | | atapi_regs[ATAPI_REG_COUNTLOW] = atapi_xferlen & 0xff; |
| 331 | | atapi_regs[ATAPI_REG_COUNTHIGH] = (atapi_xferlen>>8)&0xff; |
| 332 | | |
| 333 | | gdrom_alt_status = 0; // (I guess?) |
| 334 | | |
| 335 | | if (atapi_xferlen == 0) |
| 336 | | { |
| 337 | | // if no data to return, set the registers properly |
| 338 | | atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRDY; |
| 339 | | atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO|ATAPI_INTREASON_COMMAND; |
| 340 | | } |
| 341 | | else |
| 342 | | { |
| 343 | | // indicate data ready: set DRQ and DMA ready, and IO in INTREASON |
| 344 | | if (atapi_regs[ATAPI_REG_FEATURES] & 0x01) // DMA feature |
| 345 | | { |
| 346 | | atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_BSY | ATAPI_STAT_DRDY | ATAPI_STAT_SERVDSC; |
| 347 | | } |
| 348 | | else |
| 349 | | { |
| 350 | | atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_SERVDSC | ATAPI_STAT_DRQ; |
| 351 | | } |
| 352 | | atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO; |
| 353 | | } |
| 354 | | |
| 355 | | switch( phase ) |
| 356 | | { |
| 357 | | case SCSI_PHASE_DATAOUT: |
| 358 | | atapi_cdata_wait = atapi_xferlen; |
| 359 | | break; |
| 360 | | } |
| 361 | | |
| 362 | | // perform special ATAPI processing of certain commands |
| 363 | | switch (atapi_data[0]&0xff) |
| 364 | | { |
| 365 | | case 0x00: // BUS RESET / TEST UNIT READY |
| 366 | | case 0xbb: // SET CDROM SPEED |
| 367 | | atapi_regs[ATAPI_REG_CMDSTATUS] = 0; |
| 368 | | break; |
| 369 | | |
| 370 | | case 0x45: // PLAY |
| 371 | | atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_BSY; |
| 372 | | atapi_timer->adjust( downcast<cpu_device *>(&space->device())->cycles_to_attotime(ATAPI_CYCLES_PER_SECTOR ) ); |
| 373 | | break; |
| 374 | | } |
| 375 | | |
| 376 | | // assert IRQ |
| 377 | | gdrom_raise_irq(machine); |
| 378 | | } |
| 379 | | else |
| 380 | | { |
| 381 | | printf("ATAPI: SCSI device returned error!\n"); |
| 382 | | |
| 383 | | atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_CHECK; |
| 384 | | atapi_regs[ATAPI_REG_ERROR] = 0x50; // sense key = ILLEGAL REQUEST |
| 385 | | atapi_regs[ATAPI_REG_COUNTLOW] = 0; |
| 386 | | atapi_regs[ATAPI_REG_COUNTHIGH] = 0; |
| 387 | | } |
| 388 | | } |
| 389 | | } |
| 390 | | else |
| 391 | | { |
| 392 | | reg = offset; |
| 393 | | #if 0 |
| 394 | | switch( reg ) |
| 395 | | { |
| 396 | | case ATAPI_REG_DATA: |
| 397 | | printf( "atapi_w: data=%02x\n", data ); |
| 398 | | break; |
| 399 | | case ATAPI_REG_FEATURES: |
| 400 | | printf( "atapi_w: features=%02x\n", data ); |
| 401 | | break; |
| 402 | | case ATAPI_REG_INTREASON: |
| 403 | | printf( "atapi_w: intreason=%02x\n", data ); |
| 404 | | break; |
| 405 | | case ATAPI_REG_SAMTAG: |
| 406 | | printf( "atapi_w: samtag=%02x\n", data ); |
| 407 | | break; |
| 408 | | case ATAPI_REG_COUNTLOW: |
| 409 | | printf( "atapi_w: countlow=%02x\n", data ); |
| 410 | | break; |
| 411 | | case ATAPI_REG_COUNTHIGH: |
| 412 | | printf( "atapi_w: counthigh=%02x\n", data ); |
| 413 | | break; |
| 414 | | case ATAPI_REG_DRIVESEL: |
| 415 | | printf( "atapi_w: drivesel=%02x\n", data ); |
| 416 | | break; |
| 417 | | case ATAPI_REG_CMDSTATUS: |
| 418 | | printf( "atapi_w: cmdstatus=%02x\n", data ); |
| 419 | | break; |
| 420 | | } |
| 421 | | #endif |
| 422 | | atapi_regs[reg] = data; |
| 423 | | // mame_printf_debug("ATAPI: reg %d = %x (offset %x mask %x PC=%x)\n", reg, data, offset, mem_mask, cpu_get_pc(&space->device())); |
| 424 | | |
| 425 | | if (reg == ATAPI_REG_CMDSTATUS) |
| 426 | | { |
| 427 | | printf("ATAPI command %x issued! (PC=%x)\n", data, cpu_get_pc(&space->device())); |
| 428 | | |
| 429 | | switch (data) |
| 430 | | { |
| 431 | | case 0xa0: // PACKET |
| 432 | | atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ; |
| 433 | | gdrom_alt_status = ATAPI_STAT_DRQ; |
| 434 | | atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_COMMAND; |
| 435 | | |
| 436 | | atapi_data_ptr = 0; |
| 437 | | atapi_data_len = 0; |
| 438 | | |
| 439 | | /* we have no data */ |
| 440 | | atapi_xferlen = 0; |
| 441 | | atapi_xfermod = 0; |
| 442 | | |
| 443 | | atapi_cdata_wait = 0; |
| 444 | | break; |
| 445 | | |
| 446 | | case 0xa1: // IDENTIFY PACKET DEVICE |
| 447 | | atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ; |
| 448 | | gdrom_alt_status = ATAPI_STAT_DRQ; |
| 449 | | |
| 450 | | atapi_data_ptr = 0; |
| 451 | | atapi_data_len = 512; |
| 452 | | |
| 453 | | /* we have no data */ |
| 454 | | atapi_xferlen = 0; |
| 455 | | atapi_xfermod = 0; |
| 456 | | |
| 457 | | memset( atapi_data, 0, atapi_data_len ); |
| 458 | | |
| 459 | | atapi_data[ 0 ^ 1 ] = 0x86; // ATAPI device, cmd set 6 compliant, DRQ within 3 ms of PACKET command |
| 460 | | atapi_data[ 1 ^ 1 ] = 0x00; |
| 461 | | |
| 462 | | memset( &atapi_data[ 46 ], ' ', 8 ); |
| 463 | | atapi_data[ 46 ^ 1 ] = 'S'; |
| 464 | | atapi_data[ 47 ^ 1 ] = 'E'; |
| 465 | | |
| 466 | | memset( &atapi_data[ 54 ], ' ', 40 ); |
| 467 | | atapi_data[ 54 ^ 1 ] = 'C'; |
| 468 | | atapi_data[ 55 ^ 1 ] = 'D'; |
| 469 | | atapi_data[ 56 ^ 1 ] = '-'; |
| 470 | | atapi_data[ 57 ^ 1 ] = 'R'; |
| 471 | | atapi_data[ 58 ^ 1 ] = 'O'; |
| 472 | | atapi_data[ 59 ^ 1 ] = 'M'; |
| 473 | | atapi_data[ 60 ^ 1 ] = ' '; |
| 474 | | atapi_data[ 61 ^ 1 ] = 'D'; |
| 475 | | atapi_data[ 62 ^ 1 ] = 'R'; |
| 476 | | atapi_data[ 63 ^ 1 ] = 'I'; |
| 477 | | atapi_data[ 64 ^ 1 ] = 'V'; |
| 478 | | atapi_data[ 65 ^ 1 ] = 'E'; |
| 479 | | atapi_data[ 66 ^ 1 ] = ' '; |
| 480 | | atapi_data[ 67 ^ 1 ] = ' '; |
| 481 | | atapi_data[ 68 ^ 1 ] = ' '; |
| 482 | | atapi_data[ 69 ^ 1 ] = ' '; |
| 483 | | atapi_data[ 70 ^ 1 ] = '6'; |
| 484 | | atapi_data[ 71 ^ 1 ] = '.'; |
| 485 | | atapi_data[ 72 ^ 1 ] = '4'; |
| 486 | | atapi_data[ 73 ^ 1 ] = '2'; |
| 487 | | |
| 488 | | atapi_data[ 98 ^ 1 ] = 0x04; // IORDY may be disabled |
| 489 | | atapi_data[ 99 ^ 1 ] = 0x00; |
| 490 | | |
| 491 | | atapi_regs[ATAPI_REG_COUNTLOW] = 0; |
| 492 | | atapi_regs[ATAPI_REG_COUNTHIGH] = 2; |
| 493 | | |
| 494 | | gdrom_raise_irq(space->machine()); |
| 495 | | break; |
| 496 | | |
| 497 | | case 0xef: // SET FEATURES |
| 498 | | // set xfer mode? |
| 499 | | if (atapi_regs[ATAPI_REG_FEATURES] == 0x03) |
| 500 | | { |
| 501 | | printf("Set transfer mode to %x\n", atapi_regs[ATAPI_REG_COUNTLOW] & 0xf8); |
| 502 | | xfer_mode = atapi_regs[ATAPI_REG_COUNTLOW] & 0xf8; |
| 503 | | } |
| 504 | | else |
| 505 | | { |
| 506 | | printf("ATAPI: Unknown set features %x\n", atapi_regs[ATAPI_REG_FEATURES]); |
| 507 | | } |
| 508 | | |
| 509 | | atapi_regs[ATAPI_REG_CMDSTATUS] = 0; |
| 510 | | gdrom_alt_status = 0; // is this correct? |
| 511 | | |
| 512 | | atapi_data_ptr = 0; |
| 513 | | atapi_data_len = 0; |
| 514 | | |
| 515 | | gdrom_raise_irq(space->machine()); |
| 516 | | break; |
| 517 | | |
| 518 | | default: |
| 519 | | mame_printf_debug("ATAPI: Unknown IDE command %x\n", data); |
| 520 | | break; |
| 521 | | } |
| 522 | | } |
| 523 | | } |
| 524 | | } |
| 525 | | |
| 526 | | static void dreamcast_atapi_exit(running_machine& machine) |
| 527 | | { |
| 528 | | if (gdrom_device != NULL) |
| 529 | | { |
| 530 | | SCSIDeleteInstance( gdrom_device ); |
| 531 | | } |
| 532 | | } |
| 533 | | |
| 534 | | void dreamcast_atapi_init(running_machine &machine) |
| 535 | | { |
| 536 | | atapi_regs = auto_alloc_array(machine, UINT8, ATAPI_REG_MAX ); |
| 537 | | memset(atapi_regs, 0, sizeof(atapi_regs)); |
| 538 | | |
| 539 | | atapi_regs[ATAPI_REG_CMDSTATUS] = 0; |
| 540 | | atapi_regs[ATAPI_REG_ERROR] = 1; |
| 541 | | atapi_regs[ATAPI_REG_COUNTLOW] = 0x14; |
| 542 | | atapi_regs[ATAPI_REG_COUNTHIGH] = 0xeb; |
| 543 | | |
| 544 | | atapi_data_ptr = 0; |
| 545 | | atapi_data_len = 0; |
| 546 | | atapi_cdata_wait = 0; |
| 547 | | |
| 548 | | atapi_timer = machine.scheduler().timer_alloc(FUNC(atapi_xfer_end)); |
| 549 | | atapi_timer->adjust(attotime::never); |
| 550 | | |
| 551 | | gdrom_device = NULL; |
| 552 | | |
| 553 | | machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(dreamcast_atapi_exit),&machine)); |
| 554 | | |
| 555 | | atapi_data = auto_alloc_array(machine, UINT8, ATAPI_DATA_SIZE ); |
| 556 | | |
| 557 | | state_save_register_global_pointer(machine, atapi_regs, ATAPI_REG_MAX ); |
| 558 | | state_save_register_global_pointer(machine, atapi_data, ATAPI_DATA_SIZE / 2 ); |
| 559 | | state_save_register_global(machine, atapi_data_ptr ); |
| 560 | | state_save_register_global(machine, atapi_data_len ); |
| 561 | | state_save_register_global(machine, atapi_xferlen ); |
| 562 | | state_save_register_global(machine, atapi_xferbase ); |
| 563 | | state_save_register_global(machine, atapi_cdata_wait ); |
| 564 | | state_save_register_global(machine, atapi_xfermod ); |
| 565 | | } |
| 566 | | |
| 567 | | void dreamcast_atapi_reset(running_machine &machine) |
| 568 | | { |
| 569 | | atapi_regs[ATAPI_REG_CMDSTATUS] = 0; |
| 570 | | atapi_regs[ATAPI_REG_ERROR] = 1; |
| 571 | | atapi_regs[ATAPI_REG_COUNTLOW] = 0x14; |
| 572 | | atapi_regs[ATAPI_REG_COUNTHIGH] = 0xeb; |
| 573 | | |
| 574 | | atapi_data_ptr = 0; |
| 575 | | atapi_data_len = 0; |
| 576 | | atapi_cdata_wait = 0; |
| 577 | | |
| 578 | | atapi_xferlen = 0; |
| 579 | | atapi_xfermod = 0; |
| 580 | | |
| 581 | | if ( cd_get_cdrom_file(machine.device( "cdrom" )) != NULL ) |
| 582 | | { |
| 583 | | SCSIAllocInstance( machine, &SCSIClassGDROM, &gdrom_device, "cdrom" ); |
| 584 | | } |
| 585 | | else |
| 586 | | { |
| 587 | | gdrom_device = NULL; |
| 588 | | } |
| 589 | | } |
| 590 | | |
| 591 | | /* |
| 592 | | |
| 593 | | GDROM regsters: |
| 594 | | |
| 595 | | 5f7018: alternate status/device control |
| 596 | | 5f7080: data |
| 597 | | 5f7084: error/features |
| 598 | | 5f7088: interrupt reason/sector count |
| 599 | | 5f708c: sector number |
| 600 | | 5f7090: byte control low |
| 601 | | 5f7094: byte control high |
| 602 | | 5f7098: drive select |
| 603 | | 5f709c: status/command |
| 604 | | |
| 605 | | c002910 - ATAPI packet writes |
| 606 | | c002796 - aux status read after that |
| 607 | | c000776 - DMA triggered to c008000 |
| 608 | | |
| 609 | | */ |
| 610 | | |
| 611 | | READ64_HANDLER( dc_mess_gdrom_r ) |
| 612 | | { |
| 613 | | UINT32 off; |
| 614 | | |
| 615 | | if ((int)~mem_mask & 1) |
| 616 | | { |
| 617 | | off=(offset << 1) | 1; |
| 618 | | } |
| 619 | | else |
| 620 | | { |
| 621 | | off=offset << 1; |
| 622 | | } |
| 623 | | |
| 624 | | // printf("gdrom_r: @ %x (off %x), mask %llx (PC %x)\n", offset, off, mem_mask, cpu_get_pc(&space->device())); |
| 625 | | |
| 626 | | if (offset == 3) |
| 627 | | { |
| 628 | | return gdrom_alt_status; |
| 629 | | } |
| 630 | | else if (off >= 0x20) |
| 631 | | { |
| 632 | | return atapi_r(space, off-0x20, 0xff); |
| 633 | | } |
| 634 | | |
| 635 | | return 0; |
| 636 | | } |
| 637 | | |
| 638 | | WRITE64_HANDLER( dc_mess_gdrom_w ) |
| 639 | | { |
| 640 | | UINT32 dat,off; |
| 641 | | |
| 642 | | if ((int)~mem_mask & 1) |
| 643 | | { |
| 644 | | dat=(UINT32)(data >> 32); |
| 645 | | off=(offset << 1) | 1; |
| 646 | | } |
| 647 | | else |
| 648 | | { |
| 649 | | dat=(UINT32)data; |
| 650 | | off=offset << 1; |
| 651 | | } |
| 652 | | |
| 653 | | // printf("GDROM: [%08x=%x]write %llx to %x, mask %llx (PC %x)\n", 0x5f7000+off*4, dat, data, offset, mem_mask, cpu_get_pc(&space->device())); |
| 654 | | |
| 655 | | if (off >= 0x20) |
| 656 | | { |
| 657 | | atapi_w(space, off-0x20, dat, (UINT32)mem_mask); |
| 658 | | } |
| 659 | | } |
| 660 | | |
| 661 | | // register decode helpers |
| 662 | | |
| 663 | | // this accepts only 32-bit accesses |
| 664 | | INLINE int decode_reg32_64(running_machine &machine, UINT32 offset, UINT64 mem_mask, UINT64 *shift) |
| 665 | | { |
| 666 | | int reg = offset * 2; |
| 667 | | |
| 668 | | *shift = 0; |
| 669 | | |
| 670 | | // non 32-bit accesses have not yet been seen here, we need to know when they are |
| 671 | | if ((mem_mask != U64(0xffffffff00000000)) && (mem_mask != U64(0x00000000ffffffff))) |
| 672 | | { |
| 673 | | mame_printf_verbose("%s:Wrong mask!\n", machine.describe_context()); |
| 674 | | // debugger_break(machine); |
| 675 | | } |
| 676 | | |
| 677 | | if (mem_mask == U64(0xffffffff00000000)) |
| 678 | | { |
| 679 | | reg++; |
| 680 | | *shift = 32; |
| 681 | | } |
| 682 | | |
| 683 | | return reg; |
| 684 | | } |
| 685 | | |
| 686 | | READ64_HANDLER( dc_mess_g1_ctrl_r ) |
| 687 | | { |
| 688 | | int reg; |
| 689 | | UINT64 shift; |
| 690 | | |
| 691 | | reg = decode_reg32_64(space->machine(), offset, mem_mask, &shift); |
| 692 | | mame_printf_verbose("G1CTRL: Unmapped read %08x\n", 0x5f7400+reg*4); |
| 693 | | return (UINT64)g1bus_regs[reg] << shift; |
| 694 | | } |
| 695 | | |
| 696 | | WRITE64_HANDLER( dc_mess_g1_ctrl_w ) |
| 697 | | { |
| 698 | | int reg; |
| 699 | | UINT64 shift; |
| 700 | | UINT32 old,dat; |
| 701 | | |
| 702 | | reg = decode_reg32_64(space->machine(), offset, mem_mask, &shift); |
| 703 | | dat = (UINT32)(data >> shift); |
| 704 | | old = g1bus_regs[reg]; |
| 705 | | |
| 706 | | g1bus_regs[reg] = dat; // 5f7400+reg*4=dat |
| 707 | | mame_printf_verbose("G1CTRL: [%08x=%x] write %" I64FMT "x to %x, mask %" I64FMT "x\n", 0x5f7400+reg*4, dat, data, offset, mem_mask); |
| 708 | | switch (reg) |
| 709 | | { |
| 710 | | case SB_GDST: |
| 711 | | if (dat & 1 && g1bus_regs[SB_GDEN] == 1) // 0 -> 1 |
| 712 | | { |
| 713 | | if (g1bus_regs[SB_GDDIR] == 0) |
| 714 | | { |
| 715 | | printf("G1CTRL: unsupported transfer\n"); |
| 716 | | return; |
| 717 | | } |
| 718 | | |
| 719 | | atapi_xferbase = g1bus_regs[SB_GDSTAR]; |
| 720 | | atapi_timer->adjust(space->machine().device<cpu_device>("maincpu")->cycles_to_attotime((ATAPI_CYCLES_PER_SECTOR * (atapi_xferlen/2048)))); |
| 721 | | } |
| 722 | | break; |
| 723 | | } |
| 724 | | } |
| 725 | | |