trunk/src/emu/machine/scsibus.c
| r18343 | r18344 | |
| 1 | 1 | /* |
| 2 | | SCSIBus.c |
| 3 | 2 | |
| 4 | | Implementation of a raw SCSI/SASI bus for machines that don't use a SCSI |
| 5 | | controler chip such as the RM Nimbus, which implements it as a bunch of |
| 6 | | 74LS series chips. |
| 3 | scsibus.c |
| 7 | 4 | |
| 8 | 5 | */ |
| 9 | 6 | |
| 10 | 7 | #include "emu.h" |
| 11 | | #include "machine/scsihle.h" |
| 12 | 8 | #include "machine/scsibus.h" |
| 13 | | #include "debugger.h" |
| 14 | | #include "debug/debugcpu.h" |
| 15 | | #include "debug/debugcon.h" |
| 16 | 9 | |
| 17 | | /* |
| 18 | | LOGLEVEL |
| 19 | | 0 no logging, |
| 20 | | 1 just commands |
| 21 | | 2 1 + data |
| 22 | | 3 2 + line changes |
| 23 | | */ |
| 24 | | |
| 25 | | #define LOGLEVEL 0 |
| 26 | | |
| 27 | | #define LOG(level,...) if(LOGLEVEL>=level) logerror(__VA_ARGS__) |
| 28 | | |
| 29 | | static const char *const linenames[] = |
| 10 | void scsibus_device::scsi_update() |
| 30 | 11 | { |
| 31 | | "select", "busy", "request", "acknoledge", "C/D", "I/O", "message", "reset" |
| 32 | | }; |
| 12 | UINT32 newdata = SCSI_MASK_ALL; |
| 33 | 13 | |
| 34 | | static const char *const phasenames[] = |
| 35 | | { |
| 36 | | "data out", "data in", "command", "status", "none", "none", "message out", "message in", "bus free","select" |
| 37 | | }; |
| 38 | | |
| 39 | | void scsibus_device::dump_bytes(UINT8 *buff, int count) |
| 40 | | { |
| 41 | | int byteno; |
| 42 | | |
| 43 | | for(byteno=0; byteno<count; byteno++) |
| 14 | for( int i = 0; i < deviceCount; i++ ) |
| 44 | 15 | { |
| 45 | | logerror("%02X ",buff[byteno]); |
| 16 | newdata &= devices[ i ]->data_out; |
| 46 | 17 | } |
| 47 | | } |
| 48 | 18 | |
| 49 | | void scsibus_device::dump_command_bytes() |
| 50 | | { |
| 51 | | logerror("sending command 0x%02X to ScsiID %d\n",command[0],last_id); |
| 52 | | dump_bytes(command,cmd_idx); |
| 53 | | logerror("\n\n"); |
| 54 | | } |
| 19 | UINT32 mask = data ^ newdata; |
| 55 | 20 | |
| 56 | | void scsibus_device::dump_data_bytes(int count) |
| 57 | | { |
| 58 | | logerror("Data buffer[0..%d]\n",count); |
| 59 | | dump_bytes(buffer,count); |
| 60 | | logerror("\n\n"); |
| 61 | | } |
| 62 | | |
| 63 | | void scsibus_device::scsibus_read_data() |
| 64 | | { |
| 65 | | data_last = (bytes_left >= sectorbytes) ? sectorbytes : bytes_left; |
| 66 | | |
| 67 | | LOG(2,"SCSIBUS:scsibus_read_data bytes_left=%04X, data_last=%04X\n",bytes_left,data_last); |
| 68 | | |
| 69 | | if (data_last > 0) |
| 21 | if( mask != 0 ) |
| 70 | 22 | { |
| 71 | | devices[last_id]->ReadData(buffer, data_last); |
| 72 | | bytes_left-=data_last; |
| 73 | | } |
| 23 | data = newdata; |
| 74 | 24 | |
| 75 | | data_idx=0; |
| 76 | | } |
| 77 | | |
| 78 | | void scsibus_device::scsibus_write_data() |
| 79 | | { |
| 80 | | if (data_last > 0) |
| 81 | | { |
| 82 | | devices[last_id]->WriteData(buffer, data_last); |
| 83 | | bytes_left-=data_last; |
| 84 | | } |
| 85 | | |
| 86 | | data_idx=0; |
| 87 | | } |
| 88 | | |
| 89 | | /* SCSI Bus read/write */ |
| 90 | | |
| 91 | | UINT8 scsibus_device::scsi_data_r() |
| 92 | | { |
| 93 | | UINT8 result = 0; |
| 94 | | |
| 95 | | switch (phase) |
| 96 | | { |
| 97 | | case SCSI_PHASE_DATAIN: |
| 98 | | result=buffer[data_idx]; |
| 99 | | break; |
| 100 | | |
| 101 | | case SCSI_PHASE_STATUS: |
| 102 | | result=SCSI_STATUS_OK; // return command status |
| 103 | | break; |
| 104 | | |
| 105 | | case SCSI_PHASE_MESSAGE_IN: |
| 106 | | result=0; // no errors for the time being ! |
| 107 | | break; |
| 108 | | } |
| 109 | | |
| 110 | | LOG(2,"scsi_data_r : %02x phase=%s, data_idx=%d, cmd_idx=%d\n",result,phasenames[phase],data_idx,cmd_idx); |
| 111 | | return result; |
| 112 | | } |
| 113 | | |
| 114 | | void scsibus_device::scsi_data_w( UINT8 data ) |
| 115 | | { |
| 116 | | switch (phase) |
| 117 | | { |
| 118 | | // Note this assumes we only have one initiator and therefore |
| 119 | | // only one line active. |
| 120 | | case SCSI_PHASE_BUS_FREE: |
| 121 | | last_id=scsibus_driveno(data); |
| 122 | | sectorbytes = devices[last_id]->GetSectorBytes(); |
| 123 | | break; |
| 124 | | |
| 125 | | case SCSI_PHASE_COMMAND: |
| 126 | | command[cmd_idx]=data; |
| 127 | | break; |
| 128 | | |
| 129 | | case SCSI_PHASE_DATAOUT: |
| 130 | | |
| 131 | | //LOG(1,"SCSIBUS:bytes_left=%02X data_idx=%02X\n",bytes_left,data_idx); |
| 132 | | |
| 133 | | if(IS_COMMAND(SCSI_CMD_FORMAT_UNIT)) |
| 134 | | { |
| 135 | | // Only store the first 4 bytes of the bad block list (the header) |
| 136 | | //if(data_idx<4) |
| 137 | | buffer[data_idx]=data; |
| 138 | | dump_data_bytes(4); |
| 139 | | //else |
| 140 | | // data_idx++; |
| 141 | | |
| 142 | | // If we have the first byte, then cancel the dataout timout |
| 143 | | if(data_idx==0) |
| 144 | | dataout_timer->adjust(attotime::never); |
| 145 | | |
| 146 | | // When we have the first 3 bytes, calculate how many more are in the |
| 147 | | // bad block list. |
| 148 | | if(data_idx==2) |
| 149 | | { |
| 150 | | bytes_left+=((buffer[2]<<8)+buffer[3]); |
| 151 | | LOG(1,"format_unit reading an extra %d bytes\n",bytes_left-4); |
| 152 | | dump_data_bytes(4); |
| 153 | | } |
| 154 | | } |
| 155 | | else |
| 156 | | { |
| 157 | | buffer[data_idx]=data; |
| 158 | | } |
| 159 | | break; |
| 160 | | } |
| 161 | | } |
| 162 | | |
| 163 | | /* Get/Set lines */ |
| 164 | | |
| 165 | | UINT8 scsibus_device::get_scsi_line(UINT8 lineno) |
| 166 | | { |
| 167 | | UINT8 result=0; |
| 168 | | |
| 169 | | switch (lineno) |
| 170 | | { |
| 171 | | case SCSI_LINE_BSY: result=(linestate & (1<<SCSI_LINE_BSY)) >> SCSI_LINE_BSY; break; |
| 172 | | case SCSI_LINE_SEL: result=(linestate & (1<<SCSI_LINE_SEL)) >> SCSI_LINE_SEL; break; |
| 173 | | case SCSI_LINE_CD: result=(linestate & (1<<SCSI_LINE_CD )) >> SCSI_LINE_CD; break; |
| 174 | | case SCSI_LINE_IO: result=(linestate & (1<<SCSI_LINE_IO )) >> SCSI_LINE_IO; break; |
| 175 | | case SCSI_LINE_MSG: result=(linestate & (1<<SCSI_LINE_MSG)) >> SCSI_LINE_MSG; break; |
| 176 | | case SCSI_LINE_REQ: result=(linestate & (1<<SCSI_LINE_REQ)) >> SCSI_LINE_REQ; break; |
| 177 | | case SCSI_LINE_ACK: result=(linestate & (1<<SCSI_LINE_ACK)) >> SCSI_LINE_ACK; break; |
| 178 | | case SCSI_LINE_ATN: result=(linestate & (1<<SCSI_LINE_ATN)) >> SCSI_LINE_MSG; break; |
| 179 | | case SCSI_LINE_RST: result=(linestate & (1<<SCSI_LINE_RST)) >> SCSI_LINE_RST; break; |
| 180 | | } |
| 181 | | |
| 182 | | LOG(3,"get_scsi_line(%s)=%d\n",linenames[lineno],result); |
| 183 | | |
| 184 | | return result; |
| 185 | | } |
| 186 | | |
| 187 | | void scsibus_device::set_scsi_line(UINT8 line, UINT8 state) |
| 188 | | { |
| 189 | | UINT8 changed; |
| 190 | | |
| 191 | | changed = ((linestate & (1<<line)) != (state << line)); |
| 192 | | |
| 193 | | LOG(3,"set_scsi_line(%s,%d), changed=%d, linestate=%02X\n",linenames[line],state,changed,linestate); |
| 194 | | |
| 195 | | if(changed) |
| 196 | | { |
| 197 | | if (line==SCSI_LINE_ACK) |
| 198 | | set_scsi_line_ack(state); |
| 199 | | else |
| 200 | | set_scsi_line_now(line,state); |
| 201 | | } |
| 202 | | } |
| 203 | | |
| 204 | | void scsibus_device::set_scsi_line_now(UINT8 line, UINT8 state) |
| 205 | | { |
| 206 | | if(state) |
| 207 | | linestate |= (1<<line); |
| 208 | | else |
| 209 | | linestate &= ~(1<<line); |
| 210 | | |
| 211 | | scsi_in_line_changed(line,state); |
| 212 | | } |
| 213 | | |
| 214 | | void scsibus_device::set_scsi_line_ack(UINT8 state) |
| 215 | | { |
| 216 | | ack_timer->adjust(attotime::from_nsec(ACK_DELAY_NS),state); |
| 217 | | } |
| 218 | | |
| 219 | | void scsibus_device::scsibus_exec_command() |
| 220 | | { |
| 221 | | int command_local = 0; |
| 222 | | int newphase; |
| 223 | | |
| 224 | | if(LOGLEVEL) |
| 225 | | dump_command_bytes(); |
| 226 | | |
| 227 | | //is_linked=command[cmd_idx-1] & 0x01; |
| 228 | | is_linked=0; |
| 229 | | |
| 230 | | // Check for locally executed commands, and if found execute them |
| 231 | | switch (command[0]) |
| 232 | | { |
| 233 | | // Format unit |
| 234 | | case SCSI_CMD_FORMAT_UNIT: |
| 235 | | LOG(1,"SCSIBUS: format unit command[1]=%02X & 0x10\n",(command[1] & 0x10)); |
| 236 | | command_local=1; |
| 237 | | if((command[1] & 0x10)==0x10) |
| 238 | | devices[last_id]->SetPhase(SCSI_PHASE_DATAOUT); |
| 239 | | else |
| 240 | | devices[last_id]->SetPhase(SCSI_PHASE_STATUS); |
| 241 | | |
| 242 | | bytes_left=4; |
| 243 | | dataout_timer->adjust(attotime::from_seconds(FORMAT_UNIT_TIMEOUT)); |
| 244 | | break; |
| 245 | | |
| 246 | | case SCSI_CMD_SEARCH_DATA_EQUAL: |
| 247 | | LOG(1,"SCSIBUS: Search_data_equaln"); |
| 248 | | command_local=1; |
| 249 | | bytes_left=0; |
| 250 | | devices[last_id]->SetPhase(SCSI_PHASE_STATUS); |
| 251 | | break; |
| 252 | | |
| 253 | | case SCSI_CMD_READ_DEFECT: |
| 254 | | LOG(1,"SCSIBUS: read defect list\n"); |
| 255 | | command_local=1; |
| 256 | | |
| 257 | | buffer[0] = 0x00; |
| 258 | | buffer[1] = command[2]; |
| 259 | | buffer[3] = 0x00; // defect list len msb |
| 260 | | buffer[4] = 0x00; // defect list len lsb |
| 261 | | |
| 262 | | bytes_left=4; |
| 263 | | devices[last_id]->SetPhase(SCSI_PHASE_DATAIN); |
| 264 | | break; |
| 265 | | |
| 266 | | // write buffer |
| 267 | | case SCSI_CMD_BUFFER_WRITE: |
| 268 | | LOG(1,"SCSIBUS: write_buffer\n"); |
| 269 | | command_local=1; |
| 270 | | bytes_left=(command[7]<<8)+command[8]; |
| 271 | | devices[last_id]->SetPhase(SCSI_PHASE_DATAOUT); |
| 272 | | break; |
| 273 | | |
| 274 | | // read buffer |
| 275 | | case SCSI_CMD_BUFFER_READ: |
| 276 | | LOG(1,"SCSIBUS: read_buffer\n"); |
| 277 | | command_local=1; |
| 278 | | bytes_left=(command[7]<<8)+command[8]; |
| 279 | | devices[last_id]->SetPhase(SCSI_PHASE_DATAIN); |
| 280 | | break; |
| 281 | | } |
| 282 | | |
| 283 | | |
| 284 | | // Check for locally executed command, if not then pass it on |
| 285 | | // to the disk driver |
| 286 | | if(!command_local) |
| 287 | | { |
| 288 | | devices[last_id]->SetCommand(command, cmd_idx); |
| 289 | | devices[last_id]->ExecCommand(&bytes_left); |
| 290 | | data_idx=0; |
| 291 | | } |
| 292 | | |
| 293 | | devices[last_id]->GetPhase(&newphase); |
| 294 | | |
| 295 | | scsi_change_phase(newphase); |
| 296 | | |
| 297 | | LOG(1,"SCSIBUS:bytes_left=%02X data_idx=%02X\n",bytes_left,data_idx); |
| 298 | | |
| 299 | | // This is correct as we need to read from disk for commands other than just read data |
| 300 | | if ((phase == SCSI_PHASE_DATAIN) && (!command_local)) |
| 301 | | scsibus_read_data(); |
| 302 | | } |
| 303 | | |
| 304 | | void scsibus_device::check_process_dataout() |
| 305 | | { |
| 306 | | int capacity=0; |
| 307 | | int tracks; |
| 308 | | adaptec_sense_t *sense; |
| 309 | | |
| 310 | | LOG(1,"SCSIBUS:check_process_dataout cmd=%02X\n",command[0]); |
| 311 | | |
| 312 | | switch (command[0]) |
| 313 | | { |
| 314 | | case SCSI_CMD_MODE_SELECT: |
| 315 | | sense=(adaptec_sense_t *)buffer; |
| 316 | | tracks=(sense->cylinder_count[0]<<8)+sense->cylinder_count[1]; |
| 317 | | capacity=(tracks * sense->head_count * 17); |
| 318 | | LOG(1,"Tracks=%d, Heads=%d sec/track=%d\n",tracks,sense->head_count,sense->sectors_per_track); |
| 319 | | LOG(1,"Setting disk capacity to %d blocks\n",capacity); |
| 320 | | dump_data_bytes(0x16); |
| 321 | | //debugger_break(device->machine()); |
| 322 | | break; |
| 323 | | } |
| 324 | | } |
| 325 | | |
| 326 | | |
| 327 | | void scsibus_device::scsi_in_line_changed(UINT8 line, UINT8 state) |
| 328 | | { |
| 329 | | void *hdfile; |
| 330 | | |
| 331 | | // Reset aborts and returns to bus free |
| 332 | | if((line==SCSI_LINE_RST) && (state==0)) |
| 333 | | { |
| 334 | | scsi_change_phase(SCSI_PHASE_BUS_FREE); |
| 335 | | cmd_idx=0; |
| 336 | | data_idx=0; |
| 337 | | is_linked=0; |
| 338 | | |
| 339 | | return; |
| 340 | | } |
| 341 | | |
| 342 | | switch (phase) |
| 343 | | { |
| 344 | | case SCSI_PHASE_BUS_FREE: |
| 345 | | if((line==SCSI_LINE_SEL) && (devices[last_id]!=NULL)) |
| 346 | | { |
| 347 | | // Check to see if device had image file mounted, if not, do not set busy, |
| 348 | | // and stay busfree. |
| 349 | | devices[last_id]->GetDevice(&hdfile); |
| 350 | | if(hdfile!=(void *)NULL) |
| 351 | | { |
| 352 | | if(state==0) |
| 353 | | sel_timer->adjust(attotime::from_nsec(BSY_DELAY_NS)); |
| 354 | | else |
| 355 | | scsi_change_phase(SCSI_PHASE_COMMAND); |
| 356 | | } |
| 357 | | } |
| 358 | | break; |
| 359 | | |
| 360 | | case SCSI_PHASE_COMMAND: |
| 361 | | if(line==SCSI_LINE_ACK) |
| 362 | | { |
| 363 | | if(state) |
| 364 | | { |
| 365 | | cmd_idx++; |
| 366 | | |
| 367 | | // If the command is ready go and execute it |
| 368 | | if(cmd_idx==get_scsi_cmd_len(command[0])) |
| 369 | | { |
| 370 | | scsibus_exec_command(); |
| 371 | | } |
| 372 | | else |
| 373 | | scsi_out_line_change(SCSI_LINE_REQ,0); |
| 374 | | } |
| 375 | | else |
| 376 | | scsi_out_line_change(SCSI_LINE_REQ,1); |
| 377 | | } |
| 378 | | break; |
| 379 | | |
| 380 | | case SCSI_PHASE_DATAIN: |
| 381 | | if(line==SCSI_LINE_ACK) |
| 382 | | { |
| 383 | | if(state) |
| 384 | | { |
| 385 | | data_idx++; |
| 386 | | |
| 387 | | // check to see if we have reached the end of the block buffer |
| 388 | | // and that there is more data to read from the scsi disk |
| 389 | | if(data_idx==sectorbytes) |
| 390 | | { |
| 391 | | scsibus_read_data(); |
| 392 | | } |
| 393 | | |
| 394 | | if(data_idx == data_last && bytes_left == 0) |
| 395 | | scsi_change_phase(SCSI_PHASE_STATUS); |
| 396 | | else |
| 397 | | scsi_out_line_change(SCSI_LINE_REQ,0); |
| 398 | | } |
| 399 | | else |
| 400 | | scsi_out_line_change(SCSI_LINE_REQ,1); |
| 401 | | } |
| 402 | | break; |
| 403 | | |
| 404 | | case SCSI_PHASE_DATAOUT: |
| 405 | | if(line==SCSI_LINE_ACK) |
| 406 | | { |
| 407 | | if(state) |
| 408 | | { |
| 409 | | data_idx++; |
| 410 | | |
| 411 | | // If the data buffer is full flush it to the SCSI disk |
| 412 | | |
| 413 | | data_last = (bytes_left >= sectorbytes) ? sectorbytes : bytes_left; |
| 414 | | |
| 415 | | if(data_idx == data_last) |
| 416 | | scsibus_write_data(); |
| 417 | | |
| 418 | | if(data_idx == 0 && bytes_left == 0) |
| 419 | | { |
| 420 | | check_process_dataout(); |
| 421 | | scsi_change_phase(SCSI_PHASE_STATUS); |
| 422 | | } |
| 423 | | else |
| 424 | | scsi_out_line_change(SCSI_LINE_REQ,0); |
| 425 | | } |
| 426 | | else |
| 427 | | scsi_out_line_change(SCSI_LINE_REQ,1); |
| 428 | | } |
| 429 | | break; |
| 430 | | |
| 431 | | case SCSI_PHASE_STATUS: |
| 432 | | if(line==SCSI_LINE_ACK) |
| 433 | | { |
| 434 | | if(state) |
| 435 | | { |
| 436 | | if(cmd_idx > 0) |
| 437 | | { |
| 438 | | scsi_change_phase(SCSI_PHASE_MESSAGE_IN); |
| 439 | | } |
| 440 | | else |
| 441 | | scsi_out_line_change(SCSI_LINE_REQ,0); |
| 442 | | } |
| 443 | | else |
| 444 | | { |
| 445 | | cmd_idx++; |
| 446 | | scsi_out_line_change(SCSI_LINE_REQ,1); |
| 447 | | } |
| 448 | | } |
| 449 | | break; |
| 450 | | |
| 451 | | case SCSI_PHASE_MESSAGE_IN: |
| 452 | | if(line==SCSI_LINE_ACK) |
| 453 | | { |
| 454 | | if(state) |
| 455 | | { |
| 456 | | if(cmd_idx > 0) |
| 457 | | { |
| 458 | | if(is_linked) |
| 459 | | scsi_change_phase(SCSI_PHASE_COMMAND); |
| 460 | | else |
| 461 | | scsi_change_phase(SCSI_PHASE_BUS_FREE); |
| 462 | | } |
| 463 | | else |
| 464 | | scsi_out_line_change(SCSI_LINE_REQ,0); |
| 465 | | } |
| 466 | | else |
| 467 | | { |
| 468 | | cmd_idx++; |
| 469 | | scsi_out_line_change(SCSI_LINE_REQ,1); |
| 470 | | } |
| 471 | | } |
| 472 | | break; |
| 473 | | } |
| 474 | | } |
| 475 | | |
| 476 | | void scsibus_device::scsi_out_line_change(UINT8 line, UINT8 state) |
| 477 | | { |
| 478 | | if(line==SCSI_LINE_REQ) |
| 479 | | scsi_out_line_req(state); |
| 480 | | else |
| 481 | | scsi_out_line_change_now(line,state); |
| 482 | | } |
| 483 | | |
| 484 | | void scsibus_device::scsi_out_line_change_now(UINT8 line, UINT8 state) |
| 485 | | { |
| 486 | | if(state) |
| 487 | | linestate |= (1<<line); |
| 488 | | else |
| 489 | | linestate &= ~(1<<line); |
| 490 | | |
| 491 | | LOG(3,"scsi_out_line_change(%s,%d)\n",linenames[line],state); |
| 492 | | |
| 493 | | if(m_scsicb != NULL) |
| 494 | | { |
| 495 | | switch (line) |
| 25 | for( int i = 0; i < deviceCount; i++ ) |
| 496 | 26 | { |
| 497 | | case SCSI_LINE_BSY: m_scsicb->out_bsy_func(state); break; |
| 498 | | case SCSI_LINE_SEL: m_scsicb->out_sel_func(state); break; |
| 499 | | case SCSI_LINE_CD: m_scsicb->out_cd_func(state); break; |
| 500 | | case SCSI_LINE_IO: m_scsicb->out_io_func(state); break; |
| 501 | | case SCSI_LINE_MSG: m_scsicb->out_msg_func(state); break; |
| 502 | | case SCSI_LINE_REQ: m_scsicb->out_req_func(state); break; |
| 503 | | case SCSI_LINE_ACK: m_scsicb->out_ack_func(state); break; |
| 504 | | case SCSI_LINE_ATN: m_scsicb->out_atn_func(state); break; |
| 505 | | case SCSI_LINE_RST: m_scsicb->out_rst_func(state); break; |
| 27 | devices[ i ]->scsi_in( data, mask ); |
| 506 | 28 | } |
| 507 | 29 | } |
| 508 | 30 | } |
| 509 | 31 | |
| 510 | | void scsibus_device::scsi_out_line_req(UINT8 state) |
| 511 | | { |
| 512 | | req_timer->adjust(attotime::from_nsec(REQ_DELAY_NS),state); |
| 513 | | } |
| 514 | | |
| 515 | | void scsibus_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) |
| 516 | | { |
| 517 | | switch( tid ) |
| 518 | | { |
| 519 | | case 0: |
| 520 | | scsi_out_line_change_now(SCSI_LINE_REQ, param); |
| 521 | | break; |
| 522 | | |
| 523 | | case 1: |
| 524 | | set_scsi_line_now(SCSI_LINE_ACK, param); |
| 525 | | break; |
| 526 | | |
| 527 | | case 2: |
| 528 | | scsi_out_line_change_now(SCSI_LINE_BSY, param); |
| 529 | | break; |
| 530 | | |
| 531 | | case 3: |
| 532 | | // Some drives, notably the ST225N and ST125N, accept fromat unit commands |
| 533 | | // with flags set indicating that bad block data should be transfered but |
| 534 | | // don't then implemnt a data in phase, this timeout it to catch these ! |
| 535 | | if(IS_COMMAND(SCSI_CMD_FORMAT_UNIT) && (data_idx==0)) |
| 536 | | scsi_change_phase(SCSI_PHASE_STATUS); |
| 537 | | break; |
| 538 | | } |
| 539 | | } |
| 540 | | |
| 541 | | void scsibus_device::scsi_change_phase(UINT8 newphase) |
| 542 | | { |
| 543 | | LOG(1,"scsi_change_phase() from=%s, to=%s\n",phasenames[phase],phasenames[newphase]); |
| 544 | | |
| 545 | | phase=newphase; |
| 546 | | cmd_idx=0; |
| 547 | | data_idx=0; |
| 548 | | |
| 549 | | switch(phase) |
| 550 | | { |
| 551 | | case SCSI_PHASE_BUS_FREE: |
| 552 | | scsi_out_line_change(SCSI_LINE_CD,1); |
| 553 | | scsi_out_line_change(SCSI_LINE_IO,1); |
| 554 | | scsi_out_line_change(SCSI_LINE_MSG,1); |
| 555 | | scsi_out_line_change(SCSI_LINE_REQ,1); |
| 556 | | scsi_out_line_change(SCSI_LINE_BSY,1); |
| 557 | | LOG(1,"SCSIBUS: done\n\n"); |
| 558 | | break; |
| 559 | | |
| 560 | | case SCSI_PHASE_COMMAND: |
| 561 | | scsi_out_line_change(SCSI_LINE_CD,0); |
| 562 | | scsi_out_line_change(SCSI_LINE_IO,1); |
| 563 | | scsi_out_line_change(SCSI_LINE_MSG,1); |
| 564 | | scsi_out_line_change(SCSI_LINE_REQ,0); |
| 565 | | LOG(1,"\nSCSIBUS: Command begin\n"); |
| 566 | | break; |
| 567 | | |
| 568 | | case SCSI_PHASE_DATAOUT: |
| 569 | | scsi_out_line_change(SCSI_LINE_CD,1); |
| 570 | | scsi_out_line_change(SCSI_LINE_IO,1); |
| 571 | | scsi_out_line_change(SCSI_LINE_MSG,1); |
| 572 | | scsi_out_line_change(SCSI_LINE_REQ,0); |
| 573 | | break; |
| 574 | | |
| 575 | | case SCSI_PHASE_DATAIN: |
| 576 | | scsi_out_line_change(SCSI_LINE_CD,1); |
| 577 | | scsi_out_line_change(SCSI_LINE_IO,0); |
| 578 | | scsi_out_line_change(SCSI_LINE_MSG,1); |
| 579 | | scsi_out_line_change(SCSI_LINE_REQ,0); |
| 580 | | break; |
| 581 | | |
| 582 | | case SCSI_PHASE_STATUS: |
| 583 | | scsi_out_line_change(SCSI_LINE_CD,0); |
| 584 | | scsi_out_line_change(SCSI_LINE_IO,0); |
| 585 | | scsi_out_line_change(SCSI_LINE_MSG,1); |
| 586 | | scsi_out_line_change(SCSI_LINE_REQ,0); |
| 587 | | break; |
| 588 | | |
| 589 | | case SCSI_PHASE_MESSAGE_OUT: |
| 590 | | scsi_out_line_change(SCSI_LINE_CD,0); |
| 591 | | scsi_out_line_change(SCSI_LINE_IO,1); |
| 592 | | scsi_out_line_change(SCSI_LINE_MSG,0); |
| 593 | | scsi_out_line_change(SCSI_LINE_REQ,0); |
| 594 | | break; |
| 595 | | |
| 596 | | case SCSI_PHASE_MESSAGE_IN: |
| 597 | | scsi_out_line_change(SCSI_LINE_CD,0); |
| 598 | | scsi_out_line_change(SCSI_LINE_IO,0); |
| 599 | | scsi_out_line_change(SCSI_LINE_MSG,0); |
| 600 | | scsi_out_line_change(SCSI_LINE_REQ,0); |
| 601 | | break; |
| 602 | | } |
| 603 | | } |
| 604 | | |
| 605 | | UINT8 scsibus_device::scsibus_driveno(UINT8 drivesel) |
| 606 | | { |
| 607 | | switch (drivesel) |
| 608 | | { |
| 609 | | case 0x01: return 0; |
| 610 | | case 0x02: return 1; |
| 611 | | case 0x04: return 2; |
| 612 | | case 0x08: return 3; |
| 613 | | case 0x10: return 4; |
| 614 | | case 0x20: return 5; |
| 615 | | case 0x40: return 6; |
| 616 | | case 0x80: return 7; |
| 617 | | default: return 0; |
| 618 | | } |
| 619 | | } |
| 620 | | |
| 621 | | // get the length of a SCSI command based on it's command byte type |
| 622 | | int scsibus_device::get_scsi_cmd_len(int cbyte) |
| 623 | | { |
| 624 | | int group; |
| 625 | | |
| 626 | | group = (cbyte>>5) & 7; |
| 627 | | |
| 628 | | if (group == 0 || group == 3 || group == 6 || group == 7) return 6; |
| 629 | | if (group == 1 || group == 2) return 10; |
| 630 | | if (group == 5) return 12; |
| 631 | | |
| 632 | | fatalerror("scsibus: Unknown SCSI command group %d, command byte=%02X\n", group,cbyte); |
| 633 | | |
| 634 | | return 6; |
| 635 | | } |
| 636 | | |
| 637 | 32 | scsibus_device::scsibus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 638 | 33 | : device_t(mconfig, SCSIBUS, "SCSI bus", tag, owner, clock) |
| 639 | 34 | { |
| r18343 | r18344 | |
| 641 | 36 | |
| 642 | 37 | void scsibus_device::device_start() |
| 643 | 38 | { |
| 644 | | memset(devices, 0, sizeof(devices)); |
| 39 | deviceCount = 0; |
| 645 | 40 | |
| 646 | | // All lines start high - inactive |
| 647 | | linestate=0xFF; |
| 648 | | |
| 649 | | // Start with bus free |
| 650 | | phase=SCSI_PHASE_BUS_FREE; |
| 651 | | |
| 652 | | // Setup req/ack/sel timers |
| 653 | | req_timer=timer_alloc(0); |
| 654 | | ack_timer=timer_alloc(1); |
| 655 | | sel_timer=timer_alloc(2); |
| 656 | | dataout_timer=timer_alloc(3); |
| 657 | | |
| 658 | 41 | for( device_t *device = first_subdevice(); device != NULL; device = device->next() ) |
| 659 | 42 | { |
| 660 | | scsihle_device *scsidev = dynamic_cast<scsihle_device *>(device); |
| 43 | scsidev_device *scsidev = dynamic_cast<scsidev_device *>(device); |
| 661 | 44 | if( scsidev != NULL ) |
| 662 | 45 | { |
| 663 | | devices[scsidev->GetDeviceID()] = scsidev; |
| 46 | devices[ deviceCount++ ] = scsidev; |
| 664 | 47 | } |
| 665 | | else |
| 666 | | { |
| 667 | | scsicb_device *scsicb = dynamic_cast<scsicb_device *>(device); |
| 668 | | m_scsicb = scsicb; |
| 669 | | } |
| 670 | 48 | } |
| 49 | |
| 50 | data = SCSI_MASK_ALL; |
| 671 | 51 | } |
| 672 | 52 | |
| 673 | 53 | const device_type SCSIBUS = &device_creator<scsibus_device>; |
trunk/src/emu/machine/scsihle.c
| r18343 | r18344 | |
| 1 | | /*************************************************************************** |
| 1 | /* |
| 2 | 2 | |
| 3 | | scsihle.c - Base class for HLE'd SCSI devices. |
| 3 | scsihle.c |
| 4 | 4 | |
| 5 | | ***************************************************************************/ |
| 5 | Base class for HLE'd SCSI devices. |
| 6 | 6 | |
| 7 | | #include "emu.h" |
| 7 | */ |
| 8 | |
| 8 | 9 | #include "machine/scsihle.h" |
| 9 | 10 | |
| 10 | 11 | scsihle_device::scsihle_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : |
| r18343 | r18344 | |
| 14 | 15 | |
| 15 | 16 | void scsihle_device::device_start() |
| 16 | 17 | { |
| 18 | scsidev_device::device_start(); |
| 19 | |
| 20 | //req_timer = timer_alloc(0); |
| 21 | //ack_timer = timer_alloc(1); |
| 22 | sel_timer = timer_alloc(2); |
| 23 | dataout_timer = timer_alloc(3); |
| 24 | |
| 17 | 25 | save_item( NAME( command ) ); |
| 18 | 26 | save_item( NAME( commandLength ) ); |
| 19 | 27 | save_item( NAME( phase ) ); |
| 28 | |
| 29 | // Start with bus free |
| 30 | phase = SCSI_PHASE_BUS_FREE; |
| 20 | 31 | } |
| 21 | 32 | |
| 22 | 33 | #define SCSI_SENSE_SIZE 4 |
| r18343 | r18344 | |
| 128 | 139 | return scsiID; |
| 129 | 140 | } |
| 130 | 141 | |
| 131 | | int scsihle_device::GetSectorBytes() |
| 132 | | { |
| 133 | | return 0; |
| 134 | | } |
| 135 | | |
| 136 | 142 | void scsihle_device::static_set_deviceid( device_t &device, int _scsiID ) |
| 137 | 143 | { |
| 138 | 144 | scsihle_device &scsidev = downcast<scsihle_device &>(device); |
| r18343 | r18344 | |
| 153 | 159 | { |
| 154 | 160 | return ( *(length) << 8 ) | *(length + 1 ); |
| 155 | 161 | } |
| 162 | |
| 163 | #define BSY_DELAY_NS 50 |
| 164 | //#define REQ_DELAY_NS 90 |
| 165 | //#define ACK_DELAY_NS 90 |
| 166 | |
| 167 | static const char *const phasenames[] = |
| 168 | { |
| 169 | "data out", "data in", "command", "status", "none", "none", "message out", "message in", "bus free","select" |
| 170 | }; |
| 171 | |
| 172 | // scsidev |
| 173 | #define SCSI_CMD_BUFFER_WRITE ( 0x3b ) |
| 174 | #define SCSI_CMD_BUFFER_READ ( 0x3c ) |
| 175 | |
| 176 | // scsihd |
| 177 | #define SCSI_CMD_FORMAT_UNIT 0x04 |
| 178 | #define SCSI_CMD_SEARCH_DATA_EQUAL 0x31 |
| 179 | #define SCSI_CMD_READ_DEFECT 0x37 |
| 180 | |
| 181 | |
| 182 | #define IS_COMMAND(cmd) (command[0]==cmd) |
| 183 | #define IS_READ_COMMAND() ((command[0]==0x08) || (command[0]==0x28) || (command[0]==0xa8)) |
| 184 | #define IS_WRITE_COMMAND() ((command[0]==0x0a) || (command[0]==0x2a)) |
| 185 | |
| 186 | #define FORMAT_UNIT_TIMEOUT 5 |
| 187 | |
| 188 | struct adaptec_sense_t |
| 189 | { |
| 190 | // parameter list |
| 191 | UINT8 reserved1[3]; |
| 192 | UINT8 length; |
| 193 | |
| 194 | // descriptor list |
| 195 | UINT8 density; |
| 196 | UINT8 reserved2[4]; |
| 197 | UINT8 block_size[3]; |
| 198 | |
| 199 | // drive parameter list |
| 200 | UINT8 format_code; |
| 201 | UINT8 cylinder_count[2]; |
| 202 | UINT8 head_count; |
| 203 | UINT8 reduced_write[2]; |
| 204 | UINT8 write_precomp[2]; |
| 205 | UINT8 landing_zone; |
| 206 | UINT8 step_pulse_code; |
| 207 | UINT8 bit_flags; |
| 208 | UINT8 sectors_per_track; |
| 209 | }; |
| 210 | |
| 211 | /* |
| 212 | LOGLEVEL |
| 213 | 0 no logging, |
| 214 | 1 just commands |
| 215 | 2 1 + data |
| 216 | 3 2 + line changes |
| 217 | */ |
| 218 | |
| 219 | #define LOGLEVEL 0 |
| 220 | |
| 221 | #define LOG(level,...) if(LOGLEVEL>=level) logerror(__VA_ARGS__) |
| 222 | |
| 223 | //static const char *const linenames[] = |
| 224 | //{ |
| 225 | // "select", "busy", "request", "acknoledge", "C/D", "I/O", "message", "reset" |
| 226 | //}; |
| 227 | |
| 228 | //void scsibus_device::set_scsi_line(UINT8 line, UINT8 state) |
| 229 | //{ |
| 230 | // UINT8 changed = linestate[line] != state; |
| 231 | // |
| 232 | // LOG(3,"set_scsi_line(%s,%d), changed=%d\n",linenames[line],state,changed); |
| 233 | // |
| 234 | // if(changed) |
| 235 | // { |
| 236 | // if (line==SCSI_LINE_ACK) |
| 237 | // set_scsi_line_ack(state); |
| 238 | // else |
| 239 | // set_scsi_line_now(line,state); |
| 240 | // } |
| 241 | //} |
| 242 | // |
| 243 | //void scsibus_device::set_scsi_line_now( UINT8 line, UINT8 state ) |
| 244 | //{ |
| 245 | // if( linestate[ line ] != state ) |
| 246 | // { |
| 247 | // linestate[ line ] = state; |
| 248 | // |
| 249 | // for( int i = 0; i < deviceCount; i++ ) |
| 250 | // { |
| 251 | // devices[ i ]->scsi_in_line_changed( line, state ); |
| 252 | // } |
| 253 | // } |
| 254 | //} |
| 255 | // |
| 256 | //void scsibus_device::set_scsi_line_ack(UINT8 state) |
| 257 | //{ |
| 258 | // ack_timer->adjust(attotime::from_nsec(ACK_DELAY_NS),state); |
| 259 | //} |
| 260 | // |
| 261 | //void scsibus_device::scsi_out_line_change(UINT8 line, UINT8 state) |
| 262 | //{ |
| 263 | // if(line==SCSI_LINE_REQ) |
| 264 | // scsi_out_line_req(state); |
| 265 | // else |
| 266 | // scsi_out_line_change_now(line,state); |
| 267 | //} |
| 268 | // |
| 269 | //void scsibus_device::scsi_out_line_change_now(UINT8 line, UINT8 state) |
| 270 | //{ |
| 271 | // if( linestate[ line ] != state ) |
| 272 | // { |
| 273 | // linestate[ line ] = state; |
| 274 | // |
| 275 | // LOG(3,"scsi_out_line_change(%s,%d)\n",linenames[line],state); |
| 276 | // } |
| 277 | //} |
| 278 | // |
| 279 | //void scsibus_device::scsi_out_line_req(UINT8 state) |
| 280 | //{ |
| 281 | // req_timer->adjust(attotime::from_nsec(REQ_DELAY_NS),state); |
| 282 | //} |
| 283 | // |
| 284 | |
| 285 | void scsihle_device::dump_bytes(UINT8 *buff, int count) |
| 286 | { |
| 287 | int byteno; |
| 288 | |
| 289 | for(byteno=0; byteno<count; byteno++) |
| 290 | { |
| 291 | logerror("%02X ",buff[byteno]); |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | void scsihle_device::dump_command_bytes() |
| 296 | { |
| 297 | logerror("sending command 0x%02X to ScsiID %d\n",command[0],scsiID); |
| 298 | dump_bytes(command,cmd_idx); |
| 299 | logerror("\n\n"); |
| 300 | } |
| 301 | |
| 302 | void scsihle_device::dump_data_bytes(int count) |
| 303 | { |
| 304 | logerror("Data buffer[0..%d]\n",count); |
| 305 | dump_bytes(buffer,count); |
| 306 | logerror("\n\n"); |
| 307 | } |
| 308 | |
| 309 | void scsihle_device::scsibus_read_data() |
| 310 | { |
| 311 | data_last = (bytes_left >= sectorbytes) ? sectorbytes : bytes_left; |
| 312 | |
| 313 | LOG(2,"SCSIBUS:scsibus_read_data bytes_left=%04X, data_last=%04X\n",bytes_left,data_last); |
| 314 | |
| 315 | data_idx=0; |
| 316 | |
| 317 | if (data_last > 0) |
| 318 | { |
| 319 | ReadData(buffer, data_last); |
| 320 | bytes_left-=data_last; |
| 321 | |
| 322 | scsi_out( buffer[ data_idx++ ], SCSI_MASK_DATA ); |
| 323 | } |
| 324 | } |
| 325 | |
| 326 | void scsihle_device::scsibus_write_data() |
| 327 | { |
| 328 | if (data_last > 0) |
| 329 | { |
| 330 | WriteData(buffer, data_last); |
| 331 | bytes_left-=data_last; |
| 332 | } |
| 333 | |
| 334 | data_idx=0; |
| 335 | } |
| 336 | |
| 337 | void scsihle_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) |
| 338 | { |
| 339 | switch( tid ) |
| 340 | { |
| 341 | // case 0: |
| 342 | // scsi_out_line_change_now(SCSI_LINE_REQ, param); |
| 343 | // break; |
| 344 | // |
| 345 | // case 1: |
| 346 | // set_scsi_line_now(SCSI_LINE_ACK, param); |
| 347 | // break; |
| 348 | |
| 349 | case 2: |
| 350 | scsi_out(param * SCSI_MASK_BSY, SCSI_MASK_BSY); |
| 351 | break; |
| 352 | |
| 353 | case 3: |
| 354 | // Some drives, notably the ST225N and ST125N, accept fromat unit commands |
| 355 | // with flags set indicating that bad block data should be transfered but |
| 356 | // don't then implemnt a data in phase, this timeout it to catch these ! |
| 357 | if(IS_COMMAND(SCSI_CMD_FORMAT_UNIT) && (data_idx==0)) |
| 358 | scsi_change_phase(SCSI_PHASE_STATUS); |
| 359 | break; |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | void scsihle_device::scsibus_exec_command() |
| 364 | { |
| 365 | int command_local = 0; |
| 366 | int newphase; |
| 367 | |
| 368 | if(LOGLEVEL) |
| 369 | dump_command_bytes(); |
| 370 | |
| 371 | //is_linked=command[cmd_idx-1] & 0x01; |
| 372 | is_linked=0; |
| 373 | |
| 374 | // Check for locally executed commands, and if found execute them |
| 375 | switch (command[0]) |
| 376 | { |
| 377 | // Format unit |
| 378 | case SCSI_CMD_FORMAT_UNIT: |
| 379 | LOG(1,"SCSIBUS: format unit command[1]=%02X & 0x10\n",(command[1] & 0x10)); |
| 380 | command_local=1; |
| 381 | if((command[1] & 0x10)==0x10) |
| 382 | SetPhase(SCSI_PHASE_DATAOUT); |
| 383 | else |
| 384 | SetPhase(SCSI_PHASE_STATUS); |
| 385 | |
| 386 | bytes_left=4; |
| 387 | dataout_timer->adjust(attotime::from_seconds(FORMAT_UNIT_TIMEOUT)); |
| 388 | break; |
| 389 | |
| 390 | case SCSI_CMD_SEARCH_DATA_EQUAL: |
| 391 | LOG(1,"SCSIBUS: Search_data_equaln"); |
| 392 | command_local=1; |
| 393 | bytes_left=0; |
| 394 | SetPhase(SCSI_PHASE_STATUS); |
| 395 | break; |
| 396 | |
| 397 | case SCSI_CMD_READ_DEFECT: |
| 398 | LOG(1,"SCSIBUS: read defect list\n"); |
| 399 | command_local=1; |
| 400 | |
| 401 | buffer[0] = 0x00; |
| 402 | buffer[1] = command[2]; |
| 403 | buffer[3] = 0x00; // defect list len msb |
| 404 | buffer[4] = 0x00; // defect list len lsb |
| 405 | |
| 406 | bytes_left=4; |
| 407 | SetPhase(SCSI_PHASE_DATAIN); |
| 408 | break; |
| 409 | |
| 410 | // write buffer |
| 411 | case SCSI_CMD_BUFFER_WRITE: |
| 412 | LOG(1,"SCSIBUS: write_buffer\n"); |
| 413 | command_local=1; |
| 414 | bytes_left=(command[7]<<8)+command[8]; |
| 415 | SetPhase(SCSI_PHASE_DATAOUT); |
| 416 | break; |
| 417 | |
| 418 | // read buffer |
| 419 | case SCSI_CMD_BUFFER_READ: |
| 420 | LOG(1,"SCSIBUS: read_buffer\n"); |
| 421 | command_local=1; |
| 422 | bytes_left=(command[7]<<8)+command[8]; |
| 423 | SetPhase(SCSI_PHASE_DATAIN); |
| 424 | break; |
| 425 | } |
| 426 | |
| 427 | |
| 428 | // Check for locally executed command, if not then pass it on |
| 429 | // to the disk driver |
| 430 | if(!command_local) |
| 431 | { |
| 432 | SetCommand(command, cmd_idx); |
| 433 | ExecCommand(&bytes_left); |
| 434 | data_idx=0; |
| 435 | } |
| 436 | |
| 437 | GetPhase(&newphase); |
| 438 | |
| 439 | scsi_change_phase(newphase); |
| 440 | |
| 441 | LOG(1,"SCSIBUS:bytes_left=%02X data_idx=%02X\n",bytes_left,data_idx); |
| 442 | |
| 443 | // This is correct as we need to read from disk for commands other than just read data |
| 444 | if ((phase == SCSI_PHASE_DATAIN) && (!command_local)) |
| 445 | scsibus_read_data(); |
| 446 | } |
| 447 | |
| 448 | UINT8 scsihle_device::scsibus_driveno(UINT8 drivesel) |
| 449 | { |
| 450 | switch (drivesel) |
| 451 | { |
| 452 | case 0x01: return 0; |
| 453 | case 0x02: return 1; |
| 454 | case 0x04: return 2; |
| 455 | case 0x08: return 3; |
| 456 | case 0x10: return 4; |
| 457 | case 0x20: return 5; |
| 458 | case 0x40: return 6; |
| 459 | case 0x80: return 7; |
| 460 | default: return 0; |
| 461 | } |
| 462 | } |
| 463 | |
| 464 | void scsihle_device::scsi_change_phase(UINT8 newphase) |
| 465 | { |
| 466 | LOG(1,"scsi_change_phase() from=%s, to=%s\n",phasenames[phase],phasenames[newphase]); |
| 467 | |
| 468 | phase=newphase; |
| 469 | cmd_idx=0; |
| 470 | data_idx=0; |
| 471 | |
| 472 | switch(phase) |
| 473 | { |
| 474 | case SCSI_PHASE_BUS_FREE: |
| 475 | scsi_out( SCSI_MASK_ALL, SCSI_MASK_ALL ); |
| 476 | LOG(1,"SCSIBUS: done\n\n"); |
| 477 | break; |
| 478 | |
| 479 | case SCSI_PHASE_COMMAND: |
| 480 | scsi_out( SCSI_MASK_DATA | SCSI_MASK_IO | SCSI_MASK_MSG, SCSI_MASK_DATA | SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG | SCSI_MASK_REQ ); |
| 481 | LOG(1,"\nSCSIBUS: Command begin\n"); |
| 482 | break; |
| 483 | |
| 484 | case SCSI_PHASE_DATAOUT: |
| 485 | scsi_out( SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG, SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG | SCSI_MASK_REQ ); |
| 486 | break; |
| 487 | |
| 488 | case SCSI_PHASE_DATAIN: |
| 489 | scsi_out( SCSI_MASK_DATA | SCSI_MASK_CD | SCSI_MASK_MSG, SCSI_MASK_DATA | SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG | SCSI_MASK_REQ ); |
| 490 | break; |
| 491 | |
| 492 | case SCSI_PHASE_STATUS: |
| 493 | scsi_out( SCSI_STATUS_OK | SCSI_MASK_MSG, SCSI_MASK_DATA | SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG | SCSI_MASK_REQ ); |
| 494 | break; |
| 495 | |
| 496 | case SCSI_PHASE_MESSAGE_OUT: |
| 497 | scsi_out( SCSI_MASK_IO, SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG | SCSI_MASK_REQ ); |
| 498 | break; |
| 499 | |
| 500 | case SCSI_PHASE_MESSAGE_IN: |
| 501 | scsi_out( 0, SCSI_MASK_DATA | SCSI_MASK_CD | SCSI_MASK_IO | SCSI_MASK_MSG | SCSI_MASK_REQ );// no errors for the time being ! |
| 502 | break; |
| 503 | } |
| 504 | } |
| 505 | |
| 506 | void scsihle_device::scsi_in( UINT32 data, UINT32 mask ) |
| 507 | { |
| 508 | // Reset aborts and returns to bus free |
| 509 | if( ( mask & SCSI_MASK_RST ) != 0 && ( data & SCSI_MASK_RST ) == 0 ) |
| 510 | { |
| 511 | scsi_change_phase(SCSI_PHASE_BUS_FREE); |
| 512 | cmd_idx=0; |
| 513 | data_idx=0; |
| 514 | is_linked=0; |
| 515 | |
| 516 | return; |
| 517 | } |
| 518 | |
| 519 | switch (phase) |
| 520 | { |
| 521 | case SCSI_PHASE_BUS_FREE: |
| 522 | // Note this assumes we only have one initiator and therefore |
| 523 | // only one line active. |
| 524 | if( ( mask & SCSI_MASK_SEL ) != 0 && scsibus_driveno(data & SCSI_MASK_DATA) == scsiID) |
| 525 | { |
| 526 | void *hdfile; |
| 527 | // Check to see if device had image file mounted, if not, do not set busy, |
| 528 | // and stay busfree. |
| 529 | GetDevice(&hdfile); |
| 530 | if(hdfile!=(void *)NULL) |
| 531 | { |
| 532 | if( ( data & SCSI_MASK_SEL ) != 0 ) |
| 533 | { |
| 534 | sectorbytes = GetSectorBytes(); |
| 535 | scsi_change_phase(SCSI_PHASE_COMMAND); |
| 536 | } |
| 537 | else |
| 538 | { |
| 539 | sel_timer->adjust(attotime::from_nsec(BSY_DELAY_NS)); |
| 540 | } |
| 541 | } |
| 542 | } |
| 543 | break; |
| 544 | |
| 545 | case SCSI_PHASE_COMMAND: |
| 546 | if( ( mask & SCSI_MASK_ACK ) != 0 ) |
| 547 | { |
| 548 | if( ( data & SCSI_MASK_ACK ) != 0 ) |
| 549 | { |
| 550 | command[ cmd_idx++ ] = data & SCSI_MASK_DATA; |
| 551 | |
| 552 | // If the command is ready go and execute it |
| 553 | if(cmd_idx==get_scsi_cmd_len(command[0])) |
| 554 | { |
| 555 | scsibus_exec_command(); |
| 556 | } |
| 557 | else |
| 558 | { |
| 559 | scsi_out( 0, SCSI_MASK_REQ ); |
| 560 | } |
| 561 | } |
| 562 | else |
| 563 | { |
| 564 | scsi_out( SCSI_MASK_REQ, SCSI_MASK_REQ ); |
| 565 | } |
| 566 | } |
| 567 | break; |
| 568 | |
| 569 | case SCSI_PHASE_DATAIN: |
| 570 | if( ( mask & SCSI_MASK_ACK ) != 0 ) |
| 571 | { |
| 572 | if( ( data & SCSI_MASK_ACK ) != 0 ) |
| 573 | { |
| 574 | // check to see if we have reached the end of the block buffer |
| 575 | // and that there is more data to read from the scsi disk |
| 576 | if(data_idx==sectorbytes) |
| 577 | { |
| 578 | scsibus_read_data(); |
| 579 | } |
| 580 | |
| 581 | if(data_idx == data_last && bytes_left == 0) |
| 582 | { |
| 583 | scsi_change_phase(SCSI_PHASE_STATUS); |
| 584 | } |
| 585 | else |
| 586 | { |
| 587 | scsi_out( buffer[ data_idx++ ], SCSI_MASK_DATA | SCSI_MASK_REQ ); |
| 588 | } |
| 589 | } |
| 590 | else |
| 591 | { |
| 592 | scsi_out( SCSI_MASK_REQ, SCSI_MASK_REQ ); |
| 593 | } |
| 594 | } |
| 595 | break; |
| 596 | |
| 597 | case SCSI_PHASE_DATAOUT: |
| 598 | if( ( mask & SCSI_MASK_ACK ) != 0 ) |
| 599 | { |
| 600 | if( ( data & SCSI_MASK_ACK ) != 0 ) |
| 601 | { |
| 602 | //LOG(1,"SCSIBUS:bytes_left=%02X data_idx=%02X\n",bytes_left,data_idx); |
| 603 | buffer[data_idx++]=data & SCSI_MASK_DATA; |
| 604 | |
| 605 | if(IS_COMMAND(SCSI_CMD_FORMAT_UNIT)) |
| 606 | { |
| 607 | // If we have the first byte, then cancel the dataout timout |
| 608 | if(data_idx==1) |
| 609 | dataout_timer->adjust(attotime::never); |
| 610 | |
| 611 | // When we have the first 3 bytes, calculate how many more are in the |
| 612 | // bad block list. |
| 613 | if(data_idx==3) |
| 614 | { |
| 615 | bytes_left+=((buffer[2]<<8)+buffer[3]); |
| 616 | LOG(1,"format_unit reading an extra %d bytes\n",bytes_left-4); |
| 617 | dump_data_bytes(4); |
| 618 | } |
| 619 | } |
| 620 | |
| 621 | // If the data buffer is full flush it to the SCSI disk |
| 622 | |
| 623 | data_last = (bytes_left >= sectorbytes) ? sectorbytes : bytes_left; |
| 624 | |
| 625 | if(data_idx == data_last) |
| 626 | scsibus_write_data(); |
| 627 | |
| 628 | if(data_idx == 0 && bytes_left == 0) |
| 629 | { |
| 630 | check_process_dataout(); |
| 631 | scsi_change_phase(SCSI_PHASE_STATUS); |
| 632 | } |
| 633 | else |
| 634 | { |
| 635 | scsi_out( 0, SCSI_MASK_REQ ); |
| 636 | } |
| 637 | } |
| 638 | else |
| 639 | { |
| 640 | scsi_out( SCSI_MASK_REQ, SCSI_MASK_REQ ); |
| 641 | } |
| 642 | } |
| 643 | break; |
| 644 | |
| 645 | case SCSI_PHASE_STATUS: |
| 646 | if( ( mask & SCSI_MASK_ACK ) != 0 ) |
| 647 | { |
| 648 | if( ( data & SCSI_MASK_ACK ) != 0 ) |
| 649 | { |
| 650 | if(cmd_idx > 0) |
| 651 | { |
| 652 | scsi_change_phase(SCSI_PHASE_MESSAGE_IN); |
| 653 | } |
| 654 | else |
| 655 | { |
| 656 | scsi_out( 0, SCSI_MASK_REQ ); |
| 657 | } |
| 658 | } |
| 659 | else |
| 660 | { |
| 661 | cmd_idx++; |
| 662 | scsi_out( SCSI_MASK_REQ, SCSI_MASK_REQ ); |
| 663 | } |
| 664 | } |
| 665 | break; |
| 666 | |
| 667 | case SCSI_PHASE_MESSAGE_IN: |
| 668 | if( ( mask & SCSI_MASK_ACK ) != 0 ) |
| 669 | { |
| 670 | if( ( data & SCSI_MASK_ACK ) != 0 ) |
| 671 | { |
| 672 | if(cmd_idx > 0) |
| 673 | { |
| 674 | if(is_linked) |
| 675 | scsi_change_phase(SCSI_PHASE_COMMAND); |
| 676 | else |
| 677 | scsi_change_phase(SCSI_PHASE_BUS_FREE); |
| 678 | } |
| 679 | else |
| 680 | { |
| 681 | scsi_out( 0, SCSI_MASK_REQ ); |
| 682 | } |
| 683 | } |
| 684 | else |
| 685 | { |
| 686 | cmd_idx++; |
| 687 | scsi_out( SCSI_MASK_REQ, SCSI_MASK_REQ ); |
| 688 | } |
| 689 | } |
| 690 | break; |
| 691 | } |
| 692 | } |
| 693 | |
| 694 | void scsihle_device::check_process_dataout() |
| 695 | { |
| 696 | int capacity=0; |
| 697 | int tracks; |
| 698 | adaptec_sense_t *sense; |
| 699 | |
| 700 | LOG(1,"SCSIBUS:check_process_dataout cmd=%02X\n",command[0]); |
| 701 | |
| 702 | switch (command[0]) |
| 703 | { |
| 704 | case SCSI_CMD_MODE_SELECT: |
| 705 | sense=(adaptec_sense_t *)buffer; |
| 706 | tracks=(sense->cylinder_count[0]<<8)+sense->cylinder_count[1]; |
| 707 | capacity=(tracks * sense->head_count * 17); |
| 708 | LOG(1,"Tracks=%d, Heads=%d sec/track=%d\n",tracks,sense->head_count,sense->sectors_per_track); |
| 709 | LOG(1,"Setting disk capacity to %d blocks\n",capacity); |
| 710 | dump_data_bytes(0x16); |
| 711 | break; |
| 712 | } |
| 713 | } |
| 714 | |
| 715 | // get the length of a SCSI command based on it's command byte type |
| 716 | int scsihle_device::get_scsi_cmd_len(int cbyte) |
| 717 | { |
| 718 | int group; |
| 719 | |
| 720 | group = (cbyte>>5) & 7; |
| 721 | |
| 722 | if (group == 0 || group == 3 || group == 6 || group == 7) return 6; |
| 723 | if (group == 1 || group == 2) return 10; |
| 724 | if (group == 5) return 12; |
| 725 | |
| 726 | fatalerror("scsihle: Unknown SCSI command group %d, command byte=%02X\n", group,cbyte); |
| 727 | |
| 728 | return 6; |
| 729 | } |
trunk/src/emu/machine/scsihle.h
| r18343 | r18344 | |
| 1 | | /*************************************************************************** |
| 1 | /* |
| 2 | 2 | |
| 3 | | scsihle.h |
| 3 | scsihle.h |
| 4 | 4 | |
| 5 | | ***************************************************************************/ |
| 5 | Base class for HLE'd SCSI devices. |
| 6 | 6 | |
| 7 | */ |
| 8 | |
| 7 | 9 | #ifndef _SCSIHLE_H_ |
| 8 | 10 | #define _SCSIHLE_H_ |
| 9 | 11 | |
| 12 | #include "machine/scsibus.h" |
| 10 | 13 | #include "machine/scsidev.h" |
| 11 | 14 | |
| 12 | | // base handler |
| 13 | 15 | class scsihle_device : public scsidev_device |
| 14 | 16 | { |
| 15 | 17 | public: |
| r18343 | r18344 | |
| 26 | 28 | virtual void SetPhase( int phase ); |
| 27 | 29 | virtual void GetPhase( int *phase ); |
| 28 | 30 | virtual int GetDeviceID(); |
| 29 | | virtual int GetSectorBytes(); |
| 31 | virtual int GetSectorBytes() = 0; |
| 30 | 32 | |
| 33 | virtual void scsi_in( UINT32 data, UINT32 mask ); |
| 34 | |
| 31 | 35 | // configuration helpers |
| 32 | 36 | static void static_set_deviceid(device_t &device, int _scsiID); |
| 33 | 37 | |
| 34 | 38 | protected: |
| 35 | 39 | // device-level overrides |
| 36 | 40 | virtual void device_start(); |
| 41 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); |
| 37 | 42 | |
| 38 | 43 | private: |
| 39 | | UINT8 command[16]; |
| 44 | void scsi_change_phase(UINT8 newphase); |
| 45 | int get_scsi_cmd_len(int cbyte); |
| 46 | UINT8 scsibus_driveno(UINT8 drivesel); |
| 47 | void scsibus_read_data(); |
| 48 | void scsibus_write_data(); |
| 49 | void scsibus_exec_command(); |
| 50 | void check_process_dataout(); |
| 51 | void dump_command_bytes(); |
| 52 | void dump_data_bytes(int count); |
| 53 | void dump_bytes(UINT8 *buff, int count); |
| 54 | |
| 55 | //emu_timer *req_timer; |
| 56 | //emu_timer *ack_timer; |
| 57 | emu_timer *sel_timer; |
| 58 | emu_timer *dataout_timer; |
| 59 | |
| 60 | UINT8 command[ 32 ]; |
| 61 | UINT8 cmd_idx; |
| 62 | UINT8 is_linked; |
| 63 | |
| 64 | UINT8 buffer[ 1024 ]; |
| 65 | UINT16 data_idx; |
| 66 | int bytes_left; |
| 67 | int data_last; |
| 68 | int sectorbytes; |
| 69 | |
| 40 | 70 | int commandLength; |
| 41 | 71 | int phase; |
| 42 | 72 | int scsiID; |
| r18343 | r18344 | |
| 64 | 94 | // Status / Sense data taken from Adaptec ACB40x0 documentation. |
| 65 | 95 | // |
| 66 | 96 | |
| 67 | | #define SCSI_STATUS_OK 0x00 |
| 68 | | #define SCSI_STATUS_CHECK 0x02 |
| 69 | | #define SCSI_STATUS_EQUAL 0x04 |
| 70 | | #define SCSI_STATUS_BUSY 0x08 |
| 97 | #define SCSI_STATUS_OK 0x00 |
| 98 | #define SCSI_STATUS_CHECK 0x02 |
| 99 | #define SCSI_STATUS_EQUAL 0x04 |
| 100 | #define SCSI_STATUS_BUSY 0x08 |
| 71 | 101 | |
| 72 | | #define SCSI_SENSE_ADDR_VALID 0x80 |
| 73 | | #define SCSI_SENSE_NO_SENSE 0x00 |
| 74 | | #define SCSI_SENSE_NO_INDEX 0x01 |
| 75 | | #define SCSI_SENSE_SEEK_NOT_COMP 0x02 |
| 76 | | #define SCSI_SENSE_WRITE_FAULT 0x03 |
| 77 | | #define SCSI_SENSE_DRIVE_NOT_READY 0x04 |
| 78 | | #define SCSI_SENSE_NO_TRACK0 0x06 |
| 79 | | #define SCSI_SENSE_ID_CRC_ERROR 0x10 |
| 80 | | #define SCSI_SENSE_UNCORRECTABLE 0x11 |
| 81 | | #define SCSI_SENSE_ADDRESS_NF 0x12 |
| 82 | | #define SCSI_SENSE_RECORD_NOT_FOUND 0x14 |
| 83 | | #define SCSI_SENSE_SEEK_ERROR 0x15 |
| 84 | | #define SCSI_SENSE_DATA_CHECK_RETRY 0x18 |
| 85 | | #define SCSI_SENSE_ECC_VERIFY 0x19 |
| 86 | | #define SCSI_SENSE_INTERLEAVE_ERROR 0x1A |
| 87 | | #define SCSI_SENSE_UNFORMATTED 0x1C |
| 88 | | #define SCSI_SENSE_ILLEGAL_COMMAND 0x20 |
| 89 | | #define SCSI_SENSE_ILLEGAL_ADDRESS 0x21 |
| 90 | | #define SCSI_SENSE_VOLUME_OVERFLOW 0x23 |
| 91 | | #define SCSI_SENSE_BAD_ARGUMENT 0x24 |
| 92 | | #define SCSI_SENSE_INVALID_LUN 0x25 |
| 93 | | #define SCSI_SENSE_CART_CHANGED 0x28 |
| 94 | | #define SCSI_SENSE_ERROR_OVERFLOW 0x2C |
| 102 | #define SCSI_SENSE_ADDR_VALID 0x80 |
| 103 | #define SCSI_SENSE_NO_SENSE 0x00 |
| 104 | #define SCSI_SENSE_NO_INDEX 0x01 |
| 105 | #define SCSI_SENSE_SEEK_NOT_COMP 0x02 |
| 106 | #define SCSI_SENSE_WRITE_FAULT 0x03 |
| 107 | #define SCSI_SENSE_DRIVE_NOT_READY 0x04 |
| 108 | #define SCSI_SENSE_NO_TRACK0 0x06 |
| 109 | #define SCSI_SENSE_ID_CRC_ERROR 0x10 |
| 110 | #define SCSI_SENSE_UNCORRECTABLE 0x11 |
| 111 | #define SCSI_SENSE_ADDRESS_NF 0x12 |
| 112 | #define SCSI_SENSE_RECORD_NOT_FOUND 0x14 |
| 113 | #define SCSI_SENSE_SEEK_ERROR 0x15 |
| 114 | #define SCSI_SENSE_DATA_CHECK_RETRY 0x18 |
| 115 | #define SCSI_SENSE_ECC_VERIFY 0x19 |
| 116 | #define SCSI_SENSE_INTERLEAVE_ERROR 0x1A |
| 117 | #define SCSI_SENSE_UNFORMATTED 0x1C |
| 118 | #define SCSI_SENSE_ILLEGAL_COMMAND 0x20 |
| 119 | #define SCSI_SENSE_ILLEGAL_ADDRESS 0x21 |
| 120 | #define SCSI_SENSE_VOLUME_OVERFLOW 0x23 |
| 121 | #define SCSI_SENSE_BAD_ARGUMENT 0x24 |
| 122 | #define SCSI_SENSE_INVALID_LUN 0x25 |
| 123 | #define SCSI_SENSE_CART_CHANGED 0x28 |
| 124 | #define SCSI_SENSE_ERROR_OVERFLOW 0x2C |
| 95 | 125 | |
| 96 | 126 | // SCSI IDs |
| 97 | 127 | enum |
trunk/src/emu/machine/scsicb.c
| r18343 | r18344 | |
| 1 | /* |
| 2 | |
| 3 | scsicb.c |
| 4 | |
| 5 | Implementation of a raw SCSI/SASI bus for machines that don't use a SCSI |
| 6 | controler chip such as the RM Nimbus, which implements it as a bunch of |
| 7 | 74LS series chips. |
| 8 | |
| 9 | */ |
| 10 | |
| 1 | 11 | #include "scsicb.h" |
| 2 | 12 | #include "scsibus.h" |
| 3 | 13 | |
| r18343 | r18344 | |
| 2 | 12 | scsicb_device::scsicb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 3 | | : device_t(mconfig, SCSICB, "SCSI callback", tag, owner, clock) |
| 13 | : scsidev_device(mconfig, SCSICB, "SCSI callback", tag, owner, clock) |
| 4 | 14 | { |
| r18343 | r18344 | |
| 18 | 28 | |
| 19 | 29 | void scsicb_device::device_start() |
| 20 | 30 | { |
| 31 | scsidev_device::device_start(); |
| 32 | |
| 21 | 33 | out_bsy_func.resolve(_out_bsy_func, *this); |
| 22 | 34 | out_sel_func.resolve(_out_sel_func, *this); |
| 23 | 35 | out_cd_func.resolve(_out_cd_func, *this); |
| r18343 | r18344 | |
| 29 | 41 | out_rst_func.resolve(_out_rst_func, *this); |
| 30 | 42 | } |
| 31 | 43 | |
| 44 | void scsicb_device::scsi_in( UINT32 data, UINT32 mask ) |
| 45 | { |
| 46 | linestate = data; |
| 47 | |
| 48 | if( ( mask & SCSI_MASK_BSY ) != 0 ) |
| 49 | { |
| 50 | out_bsy_func( (int) ( data & SCSI_MASK_BSY ) != 0 ); |
| 51 | } |
| 52 | |
| 53 | if( ( mask & SCSI_MASK_SEL ) != 0 ) |
| 54 | { |
| 55 | out_sel_func( (int) ( data & SCSI_MASK_SEL ) != 0 ); |
| 56 | } |
| 57 | |
| 58 | if( ( mask & SCSI_MASK_CD ) != 0 ) |
| 59 | { |
| 60 | out_cd_func( (int) ( data & SCSI_MASK_CD ) != 0 ); |
| 61 | } |
| 62 | |
| 63 | if( ( mask & SCSI_MASK_IO ) != 0 ) |
| 64 | { |
| 65 | out_io_func( (int) ( data & SCSI_MASK_IO ) != 0 ); |
| 66 | } |
| 67 | |
| 68 | if( ( mask & SCSI_MASK_MSG ) != 0 ) |
| 69 | { |
| 70 | out_msg_func( (int) ( data & SCSI_MASK_MSG ) != 0 ); |
| 71 | } |
| 72 | |
| 73 | if( ( mask & SCSI_MASK_REQ ) != 0 ) |
| 74 | { |
| 75 | out_req_func( (int) ( data & SCSI_MASK_REQ ) != 0 ); |
| 76 | } |
| 77 | |
| 78 | if( ( mask & SCSI_MASK_ACK ) != 0 ) |
| 79 | { |
| 80 | out_ack_func( (int) ( data & SCSI_MASK_ACK ) != 0 ); |
| 81 | } |
| 82 | |
| 83 | if( ( mask & SCSI_MASK_ATN ) != 0 ) |
| 84 | { |
| 85 | out_ack_func( (int) ( data & SCSI_MASK_ATN ) != 0 ); |
| 86 | } |
| 87 | |
| 88 | if( ( mask & SCSI_MASK_RST ) != 0 ) |
| 89 | { |
| 90 | out_rst_func( (int) ( data & SCSI_MASK_RST ) != 0 ); |
| 91 | } |
| 92 | } |
| 93 | |
| 32 | 94 | UINT8 scsicb_device::scsi_data_r() |
| 33 | 95 | { |
| 34 | | scsibus_device *m_scsibus = downcast<scsibus_device *>( owner() ); |
| 35 | | return m_scsibus->scsi_data_r(); |
| 96 | return linestate & SCSI_MASK_DATA; |
| 36 | 97 | } |
| 37 | 98 | |
| 38 | 99 | void scsicb_device::scsi_data_w( UINT8 data ) |
| 39 | 100 | { |
| 40 | | scsibus_device *m_scsibus = downcast<scsibus_device *>( owner() ); |
| 41 | | m_scsibus->scsi_data_w( data ); |
| 101 | scsi_out( data, SCSI_MASK_DATA ); |
| 42 | 102 | } |
| 43 | 103 | |
| 44 | | UINT8 scsicb_device::get_scsi_line( UINT8 line ) |
| 104 | UINT8 scsicb_device::get_scsi_line( UINT32 line ) |
| 45 | 105 | { |
| 46 | | scsibus_device *m_scsibus = downcast<scsibus_device *>( owner() ); |
| 47 | | return m_scsibus->get_scsi_line( line ); |
| 106 | UINT8 result = (int)( ( linestate & line ) != 0 ); |
| 107 | |
| 108 | // LOG(3,"get_scsi_line(%s)=%d\n",linenames[lineno],result); |
| 109 | |
| 110 | return result; |
| 48 | 111 | } |
| 49 | 112 | |
| 50 | | void scsicb_device::set_scsi_line( UINT8 line, UINT8 state ) |
| 113 | void scsicb_device::set_scsi_line( UINT32 mask, UINT8 state ) |
| 51 | 114 | { |
| 52 | | scsibus_device *m_scsibus = downcast<scsibus_device *>( owner() ); |
| 53 | | m_scsibus->set_scsi_line( line, state ); |
| 115 | scsi_out( state * mask, mask ); |
| 54 | 116 | } |
| 55 | 117 | |
| 56 | 118 | READ8_MEMBER( scsicb_device::scsi_data_r ) |
| r18343 | r18344 | |
| 63 | 125 | scsi_data_w( data ); |
| 64 | 126 | } |
| 65 | 127 | |
| 66 | | READ_LINE_MEMBER( scsicb_device::scsi_bsy_r ) { return get_scsi_line(SCSI_LINE_BSY); } |
| 67 | | READ_LINE_MEMBER( scsicb_device::scsi_sel_r ) { return get_scsi_line(SCSI_LINE_SEL); } |
| 68 | | READ_LINE_MEMBER( scsicb_device::scsi_cd_r ) { return get_scsi_line(SCSI_LINE_CD); } |
| 69 | | READ_LINE_MEMBER( scsicb_device::scsi_io_r ) { return get_scsi_line(SCSI_LINE_IO); } |
| 70 | | READ_LINE_MEMBER( scsicb_device::scsi_msg_r ) { return get_scsi_line(SCSI_LINE_MSG); } |
| 71 | | READ_LINE_MEMBER( scsicb_device::scsi_req_r ) { return get_scsi_line(SCSI_LINE_REQ); } |
| 72 | | READ_LINE_MEMBER( scsicb_device::scsi_ack_r ) { return get_scsi_line(SCSI_LINE_ACK); } |
| 73 | | READ_LINE_MEMBER( scsicb_device::scsi_atn_r ) { return get_scsi_line(SCSI_LINE_ATN); } |
| 74 | | READ_LINE_MEMBER( scsicb_device::scsi_rst_r ) { return get_scsi_line(SCSI_LINE_RST); } |
| 128 | READ_LINE_MEMBER( scsicb_device::scsi_bsy_r ) { return get_scsi_line(SCSI_MASK_BSY); } |
| 129 | READ_LINE_MEMBER( scsicb_device::scsi_sel_r ) { return get_scsi_line(SCSI_MASK_SEL); } |
| 130 | READ_LINE_MEMBER( scsicb_device::scsi_cd_r ) { return get_scsi_line(SCSI_MASK_CD); } |
| 131 | READ_LINE_MEMBER( scsicb_device::scsi_io_r ) { return get_scsi_line(SCSI_MASK_IO); } |
| 132 | READ_LINE_MEMBER( scsicb_device::scsi_msg_r ) { return get_scsi_line(SCSI_MASK_MSG); } |
| 133 | READ_LINE_MEMBER( scsicb_device::scsi_req_r ) { return get_scsi_line(SCSI_MASK_REQ); } |
| 134 | READ_LINE_MEMBER( scsicb_device::scsi_ack_r ) { return get_scsi_line(SCSI_MASK_ACK); } |
| 135 | READ_LINE_MEMBER( scsicb_device::scsi_atn_r ) { return get_scsi_line(SCSI_MASK_ATN); } |
| 136 | READ_LINE_MEMBER( scsicb_device::scsi_rst_r ) { return get_scsi_line(SCSI_MASK_RST); } |
| 75 | 137 | |
| 76 | | WRITE_LINE_MEMBER( scsicb_device::scsi_bsy_w ) { set_scsi_line(SCSI_LINE_BSY, state); } |
| 77 | | WRITE_LINE_MEMBER( scsicb_device::scsi_sel_w ) { set_scsi_line(SCSI_LINE_SEL, state); } |
| 78 | | WRITE_LINE_MEMBER( scsicb_device::scsi_cd_w ) { set_scsi_line(SCSI_LINE_CD, state); } |
| 79 | | WRITE_LINE_MEMBER( scsicb_device::scsi_io_w ) { set_scsi_line(SCSI_LINE_IO, state); } |
| 80 | | WRITE_LINE_MEMBER( scsicb_device::scsi_msg_w ) { set_scsi_line(SCSI_LINE_MSG, state); } |
| 81 | | WRITE_LINE_MEMBER( scsicb_device::scsi_req_w ) { set_scsi_line(SCSI_LINE_REQ, state); } |
| 82 | | WRITE_LINE_MEMBER( scsicb_device::scsi_ack_w ) { set_scsi_line(SCSI_LINE_ACK, state); } |
| 83 | | WRITE_LINE_MEMBER( scsicb_device::scsi_atn_w ) { set_scsi_line(SCSI_LINE_ATN, state); } |
| 84 | | WRITE_LINE_MEMBER( scsicb_device::scsi_rst_w ) { set_scsi_line(SCSI_LINE_RST, state); } |
| 138 | WRITE_LINE_MEMBER( scsicb_device::scsi_bsy_w ) { set_scsi_line(SCSI_MASK_BSY, state); } |
| 139 | WRITE_LINE_MEMBER( scsicb_device::scsi_sel_w ) { set_scsi_line(SCSI_MASK_SEL, state); } |
| 140 | WRITE_LINE_MEMBER( scsicb_device::scsi_cd_w ) { set_scsi_line(SCSI_MASK_CD, state); } |
| 141 | WRITE_LINE_MEMBER( scsicb_device::scsi_io_w ) { set_scsi_line(SCSI_MASK_IO, state); } |
| 142 | WRITE_LINE_MEMBER( scsicb_device::scsi_msg_w ) { set_scsi_line(SCSI_MASK_MSG, state); } |
| 143 | WRITE_LINE_MEMBER( scsicb_device::scsi_req_w ) { set_scsi_line(SCSI_MASK_REQ, state); } |
| 144 | WRITE_LINE_MEMBER( scsicb_device::scsi_ack_w ) { set_scsi_line(SCSI_MASK_ACK, state); } |
| 145 | WRITE_LINE_MEMBER( scsicb_device::scsi_atn_w ) { set_scsi_line(SCSI_MASK_ATN, state); } |
| 146 | WRITE_LINE_MEMBER( scsicb_device::scsi_rst_w ) { set_scsi_line(SCSI_MASK_RST, state); } |
| 85 | 147 | |
| 86 | 148 | const device_type SCSICB = &device_creator<scsicb_device>; |