src/mess/machine/scsibus.c
| r0 | r7052 | |
| 1 | /*
|
| 2 | SCSIBus.c
|
| 3 | |
| 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.
|
| 7 | |
| 8 | */
|
| 9 | |
| 10 | #include "machine/scsi.h"
|
| 11 | #include "machine/scsibus.h"
|
| 12 | |
| 13 | /* LOGLEVEL 0=no logging, 1=just commands and data, 2=everything ! */
|
| 14 | |
| 15 | #define LOGLEVEL 0
|
| 16 | |
| 17 | #define LOG(level,...) if(LOGLEVEL>=level) logerror(__VA_ARGS__)
|
| 18 | |
| 19 | typedef struct _scsibus_t scsibus_t;
|
| 20 | struct _scsibus_t
|
| 21 | {
|
| 22 | SCSIInstance *devices[8];
|
| 23 | const SCSIBus_interface *interface;
|
| 24 | |
| 25 | UINT8 linestate;
|
| 26 | UINT8 last_id;
|
| 27 | UINT8 command[CMD_BUF_SIZE];
|
| 28 | UINT8 data[DATA_BUF_SIZE];
|
| 29 | UINT8 cmd_idx;
|
| 30 | UINT16 data_idx;
|
| 31 | int xfer_count;
|
| 32 | int bytes_left;
|
| 33 | UINT8 phase;
|
| 34 | UINT8 is_linked;
|
| 35 | |
| 36 | emu_timer *req_timer;
|
| 37 | emu_timer *ack_timer;
|
| 38 | |
| 39 | UINT8 timer_flag;
|
| 40 | |
| 41 | running_machine *machine;
|
| 42 | |
| 43 | UINT8 initialised;
|
| 44 | };
|
| 45 | |
| 46 | static void set_scsi_line_now(const device_config *device, UINT8 line, UINT8 state);
|
| 47 | static void set_scsi_line_ack(const device_config *device, UINT8 state);
|
| 48 | static void scsi_in_line_changed(const device_config *device, UINT8 line, UINT8 state);
|
| 49 | static void scsi_out_line_change(const device_config *device, UINT8 line, UINT8 state);
|
| 50 | static void scsi_out_line_change_now(const device_config *device, UINT8 line, UINT8 state);
|
| 51 | static void scsi_out_line_req(const device_config *device, UINT8 state);
|
| 52 | static TIMER_CALLBACK(req_timer_callback);
|
| 53 | static TIMER_CALLBACK(ack_timer_callback);
|
| 54 | static void scsi_change_phase(const device_config *device, UINT8 newphase);
|
| 55 | |
| 56 | static const char *const linenames[] = |
| 57 | {
|
| 58 | "select", "busy", "request", "acknoledge", "C/D", "I/O", "message", "reset"
|
| 59 | };
|
| 60 | |
| 61 | static const char *const phasenames[] = |
| 62 | {
|
| 63 | "data out", "data in", "command", "status", "none", "none", "message out", "message in", "bus free","select"
|
| 64 | };
|
| 65 | |
| 66 | INLINE scsibus_t *get_token(const device_config *device)
|
| 67 | {
|
| 68 | assert(device->type == SCSIBUS);
|
| 69 | return (scsibus_t *) device->token;
|
| 70 | }
|
| 71 | |
| 72 | static void scsibus_read_data(scsibus_t *bus)
|
| 73 | { |
| 74 | if(bus->bytes_left >= DATA_BUF_SIZE)
|
| 75 | {
|
| 76 | SCSIReadData(bus->devices[bus->last_id], bus->data, DATA_BUF_SIZE);
|
| 77 | |
| 78 | bus->bytes_left-=DATA_BUF_SIZE;
|
| 79 | bus->data_idx=0;
|
| 80 | }
|
| 81 | }
|
| 82 | |
| 83 | static void scsibus_write_data(scsibus_t *bus)
|
| 84 | {
|
| 85 | if(bus->bytes_left >= DATA_BUF_SIZE)
|
| 86 | {
|
| 87 | SCSIWriteData(bus->devices[bus->last_id], bus->data, DATA_BUF_SIZE);
|
| 88 | |
| 89 | bus->bytes_left-=DATA_BUF_SIZE;
|
| 90 | bus->data_idx=0;
|
| 91 | }
|
| 92 | }
|
| 93 | |
| 94 | /* SCSI Bus read/write */
|
| 95 | |
| 96 | UINT8 scsi_data_r(const device_config *device)
|
| 97 | {
|
| 98 | scsibus_t *bus = get_token(device);
|
| 99 | UINT8 result = 0;
|
| 100 | |
| 101 | switch (bus->phase)
|
| 102 | {
|
| 103 | case SCSI_PHASE_DATAIN : |
| 104 | result=bus->data[bus->data_idx++];
|
| 105 | |
| 106 | // check to see if we have reached the end of the block buffer
|
| 107 | // and that there is more data to read from the scsi disk
|
| 108 | if((bus->data_idx==DATA_BUF_SIZE) && (bus->bytes_left>0))
|
| 109 | {
|
| 110 | scsibus_read_data(bus);
|
| 111 | }
|
| 112 | break;
|
| 113 | |
| 114 | case SCSI_PHASE_STATUS : |
| 115 | result=0; // no errors for the time being !
|
| 116 | bus->cmd_idx++;
|
| 117 | break;
|
| 118 | |
| 119 | case SCSI_PHASE_MESSAGE_IN : |
| 120 | result=0; // no errors for the time being !
|
| 121 | bus->cmd_idx++;
|
| 122 | break;
|
| 123 | }
|
| 124 | |
| 125 | LOG(2,"scsi_data_r : phase=%s, data_idx=%d, cmd_idx=%d\n",phasenames[bus->phase],bus->data_idx,bus->cmd_idx);
|
| 126 | return result;
|
| 127 | }
|
| 128 | |
| 129 | void scsi_data_w(const device_config *device, UINT8 data)
|
| 130 | {
|
| 131 | scsibus_t *bus = get_token(device);
|
| 132 | |
| 133 | switch (bus->phase)
|
| 134 | {
|
| 135 | // Note this assumes we only have one initiator and therefore
|
| 136 | // only one line active.
|
| 137 | case SCSI_PHASE_BUS_FREE :
|
| 138 | bus->last_id=driveno(data);
|
| 139 | break;
|
| 140 | |
| 141 | case SCSI_PHASE_COMMAND :
|
| 142 | bus->command[bus->cmd_idx++]=data;
|
| 143 | break;
|
| 144 | |
| 145 | case SCSI_PHASE_DATAOUT :
|
| 146 | bus->data[bus->data_idx++]=data;
|
| 147 | |
| 148 | // If the data buffer is full, flush it to the SCSI disk
|
| 149 | if(bus->data_idx == DATA_BUF_SIZE)
|
| 150 | scsibus_write_data(bus);
|
| 151 | break;
|
| 152 | }
|
| 153 | }
|
| 154 | |
| 155 | /* Get/Set lines */
|
| 156 | |
| 157 | UINT8 get_scsi_lines(const device_config *device)
|
| 158 | {
|
| 159 | scsibus_t *bus = get_token(device);
|
| 160 | |
| 161 | return bus->linestate;
|
| 162 | }
|
| 163 | |
| 164 | UINT8 get_scsi_line(const device_config *device, UINT8 lineno)
|
| 165 | {
|
| 166 | scsibus_t *bus = get_token(device);
|
| 167 | UINT8 result=0;
|
| 168 | |
| 169 | switch (lineno)
|
| 170 | {
|
| 171 | case SCSI_LINE_SEL : result=(bus->linestate & (1<<SCSI_LINE_SEL)) >> SCSI_LINE_SEL;
|
| 172 | case SCSI_LINE_BSY : result=(bus->linestate & (1<<SCSI_LINE_BSY)) >> SCSI_LINE_BSY;
|
| 173 | case SCSI_LINE_REQ : result=(bus->linestate & (1<<SCSI_LINE_REQ)) >> SCSI_LINE_REQ;
|
| 174 | case SCSI_LINE_ACK : result=(bus->linestate & (1<<SCSI_LINE_ACK)) >> SCSI_LINE_ACK;
|
| 175 | case SCSI_LINE_CD : result=(bus->linestate & (1<<SCSI_LINE_CD )) >> SCSI_LINE_CD;
|
| 176 | case SCSI_LINE_IO : result=(bus->linestate & (1<<SCSI_LINE_IO )) >> SCSI_LINE_IO;
|
| 177 | case SCSI_LINE_MSG : result=(bus->linestate & (1<<SCSI_LINE_MSG)) >> SCSI_LINE_MSG;
|
| 178 | case SCSI_LINE_RESET : result=(bus->linestate & (1<<SCSI_LINE_RESET)) >> SCSI_LINE_RESET;
|
| 179 | }
|
| 180 | |
| 181 | LOG(2,"get_scsi_line(%s)=%d\n",linenames[lineno],result);
|
| 182 | |
| 183 | return result;
|
| 184 | }
|
| 185 | |
| 186 | void set_scsi_line(const device_config *device, UINT8 line, UINT8 state)
|
| 187 | {
|
| 188 | scsibus_t *bus = get_token(device);
|
| 189 | UINT8 changed;
|
| 190 | |
| 191 | changed = ((bus->linestate & (1<<line)) != (state << line));
|
| 192 | |
| 193 | LOG(2,"set_scsi_line(%s,%d), changed=%d, linestate=%02X\n",linenames[line],state,changed,bus->linestate);
|
| 194 | |
| 195 | if(changed)
|
| 196 | {
|
| 197 | if (line==SCSI_LINE_ACK)
|
| 198 | set_scsi_line_ack(device,state);
|
| 199 | else
|
| 200 | set_scsi_line_now(device,line,state);
|
| 201 | }
|
| 202 | }
|
| 203 | |
| 204 | static void set_scsi_line_now(const device_config *device, UINT8 line, UINT8 state)
|
| 205 | {
|
| 206 | scsibus_t *bus = get_token(device);
|
| 207 | |
| 208 | if(state) |
| 209 | bus->linestate |= (1<<line);
|
| 210 | else
|
| 211 | bus->linestate &= ~(1<<line);
|
| 212 | |
| 213 | scsi_in_line_changed(device,line,state);
|
| 214 | }
|
| 215 | |
| 216 | void set_scsi_line_ack(const device_config *device, UINT8 state)
|
| 217 | {
|
| 218 | scsibus_t *bus = get_token(device);
|
| 219 | |
| 220 | timer_adjust_oneshot(bus->ack_timer,ATTOTIME_IN_NSEC(ACK_DELAY_NS),state);
|
| 221 | }
|
| 222 | |
| 223 | void dump_command_bytes(scsibus_t *bus)
|
| 224 | {
|
| 225 | int byteno;
|
| 226 | |
| 227 | logerror("sending command %0X to ScsiID %d\n",bus->command[0],bus->last_id);
|
| 228 | |
| 229 | for(byteno=0; byteno<bus->cmd_idx; byteno++)
|
| 230 | {
|
| 231 | logerror("%02X ",bus->command[byteno]);
|
| 232 | }
|
| 233 | logerror("\n\n");
|
| 234 | }
|
| 235 | |
| 236 | static void scsi_in_line_changed(const device_config *device, UINT8 line, UINT8 state)
|
| 237 | {
|
| 238 | scsibus_t *bus = get_token(device);
|
| 239 | int newphase;
|
| 240 | |
| 241 | // Reset aborts and returns to bus free
|
| 242 | if((line==SCSI_LINE_RESET) && (state==0))
|
| 243 | {
|
| 244 | scsi_change_phase(device,SCSI_PHASE_BUS_FREE);
|
| 245 | bus->cmd_idx=0;
|
| 246 | bus->data_idx=0;
|
| 247 | bus->is_linked=0;
|
| 248 | |
| 249 | return;
|
| 250 | }
|
| 251 | |
| 252 | switch (bus->phase)
|
| 253 | {
|
| 254 | case SCSI_PHASE_BUS_FREE :
|
| 255 | if((line==SCSI_LINE_SEL) && (bus->devices[bus->last_id]!=NULL))
|
| 256 | {
|
| 257 | if(state==0)
|
| 258 | scsi_out_line_change(device,SCSI_LINE_BSY,0);
|
| 259 | else
|
| 260 | scsi_change_phase(device,SCSI_PHASE_COMMAND);
|
| 261 | }
|
| 262 | break;
|
| 263 | |
| 264 | case SCSI_PHASE_COMMAND :
|
| 265 | if(line==SCSI_LINE_ACK)
|
| 266 | {
|
| 267 | if(state)
|
| 268 | {
|
| 269 | // If the command is ready go and execute it
|
| 270 | if(bus->cmd_idx==get_scsi_cmd_len(bus->command[0]))
|
| 271 | {
|
| 272 | dump_command_bytes(bus);
|
| 273 | bus->is_linked=bus->command[bus->cmd_idx-1] & 0x01;
|
| 274 | SCSISetCommand(bus->devices[bus->last_id], bus->command, bus->cmd_idx);
|
| 275 | SCSIExecCommand(bus->devices[bus->last_id], &bus->xfer_count);
|
| 276 | SCSIGetPhase(bus->devices[bus->last_id], &newphase);
|
| 277 | |
| 278 | scsi_change_phase(device,newphase);
|
| 279 | |
| 280 | bus->bytes_left=bus->xfer_count;
|
| 281 | bus->data_idx=0;
|
| 282 | |
| 283 | if (bus->phase == SCSI_PHASE_DATAIN)
|
| 284 | scsibus_read_data(bus);
|
| 285 | }
|
| 286 | else
|
| 287 | scsi_out_line_change(device,SCSI_LINE_REQ,0);
|
| 288 | }
|
| 289 | else
|
| 290 | scsi_out_line_change(device,SCSI_LINE_REQ,1);
|
| 291 | }
|
| 292 | break;
|
| 293 | |
| 294 | case SCSI_PHASE_DATAIN : |
| 295 | if(line==SCSI_LINE_ACK) |
| 296 | {
|
| 297 | if(state)
|
| 298 | {
|
| 299 | if((bus->data_idx == DATA_BUF_SIZE-1) && (bus->bytes_left == 0))
|
| 300 | scsi_change_phase(device,SCSI_PHASE_STATUS);
|
| 301 | else
|
| 302 | scsi_out_line_change(device,SCSI_LINE_REQ,0);
|
| 303 | }
|
| 304 | else
|
| 305 | scsi_out_line_change(device,SCSI_LINE_REQ,1);
|
| 306 | }
|
| 307 | break;
|
| 308 | |
| 309 | case SCSI_PHASE_DATAOUT : |
| 310 | if(line==SCSI_LINE_ACK) |
| 311 | {
|
| 312 | if(state)
|
| 313 | {
|
| 314 | if((bus->data_idx == 0) && (bus->bytes_left == 0))
|
| 315 | scsi_change_phase(device,SCSI_PHASE_STATUS);
|
| 316 | else
|
| 317 | scsi_out_line_change(device,SCSI_LINE_REQ,0);
|
| 318 | }
|
| 319 | else
|
| 320 | scsi_out_line_change(device,SCSI_LINE_REQ,1);
|
| 321 | }
|
| 322 | break;
|
| 323 | |
| 324 | case SCSI_PHASE_STATUS : |
| 325 | if(line==SCSI_LINE_ACK) |
| 326 | {
|
| 327 | if(state)
|
| 328 | {
|
| 329 | if(bus->cmd_idx > 0)
|
| 330 | {
|
| 331 | scsi_change_phase(device,SCSI_PHASE_MESSAGE_IN);
|
| 332 | }
|
| 333 | else
|
| 334 | scsi_out_line_change(device,SCSI_LINE_REQ,0);
|
| 335 | }
|
| 336 | else
|
| 337 | scsi_out_line_change(device,SCSI_LINE_REQ,1);
|
| 338 | }
|
| 339 | break;
|
| 340 | |
| 341 | case SCSI_PHASE_MESSAGE_IN : |
| 342 | if(line==SCSI_LINE_ACK) |
| 343 | {
|
| 344 | if(state)
|
| 345 | {
|
| 346 | if(bus->cmd_idx > 0)
|
| 347 | {
|
| 348 | if(bus->is_linked)
|
| 349 | scsi_change_phase(device,SCSI_PHASE_COMMAND);
|
| 350 | else
|
| 351 | scsi_change_phase(device,SCSI_PHASE_BUS_FREE);
|
| 352 | }
|
| 353 | else
|
| 354 | scsi_out_line_change(device,SCSI_LINE_REQ,0);
|
| 355 | }
|
| 356 | else
|
| 357 | scsi_out_line_change(device,SCSI_LINE_REQ,1);
|
| 358 | }
|
| 359 | break;
|
| 360 | }
|
| 361 | }
|
| 362 | |
| 363 | static void scsi_out_line_change(const device_config *device, UINT8 line, UINT8 state)
|
| 364 | {
|
| 365 | if(line==SCSI_LINE_REQ)
|
| 366 | scsi_out_line_req(device,state);
|
| 367 | else
|
| 368 | scsi_out_line_change_now(device,line,state);
|
| 369 | }
|
| 370 | |
| 371 | static void scsi_out_line_change_now(const device_config *device, UINT8 line, UINT8 state)
|
| 372 | { |
| 373 | scsibus_t *bus = get_token(device);
|
| 374 | |
| 375 | if(state)
|
| 376 | bus->linestate |= (1<<line);
|
| 377 | else
|
| 378 | bus->linestate &= ~(1<<line);
|
| 379 | |
| 380 | LOG(2,"scsi_out_line_change(%s,%d)\n",linenames[line],state);
|
| 381 | |
| 382 | if(bus->interface->line_change_cb!=NULL)
|
| 383 | bus->interface->line_change_cb(device,line,state);
|
| 384 | }
|
| 385 | |
| 386 | static void scsi_out_line_req(const device_config *device, UINT8 state)
|
| 387 | {
|
| 388 | scsibus_t *bus = get_token(device);
|
| 389 | |
| 390 | timer_adjust_oneshot(bus->req_timer,ATTOTIME_IN_NSEC(REQ_DELAY_NS),state);
|
| 391 | }
|
| 392 | |
| 393 | |
| 394 | static TIMER_CALLBACK(req_timer_callback)
|
| 395 | {
|
| 396 | scsi_out_line_change_now(ptr, SCSI_LINE_REQ, param);
|
| 397 | }
|
| 398 | |
| 399 | static TIMER_CALLBACK(ack_timer_callback)
|
| 400 | {
|
| 401 | set_scsi_line_now(ptr, SCSI_LINE_ACK, param);
|
| 402 | }
|
| 403 | |
| 404 | |
| 405 | UINT8 get_scsi_phase(const device_config *device)
|
| 406 | {
|
| 407 | scsibus_t *bus = get_token(device);
|
| 408 | |
| 409 | return bus->phase;
|
| 410 | }
|
| 411 | |
| 412 | |
| 413 | static void scsi_change_phase(const device_config *device, UINT8 newphase)
|
| 414 | {
|
| 415 | scsibus_t *bus = get_token(device);
|
| 416 | |
| 417 | LOG(1,"scsi_change_phase() from=%s, to=%s\n",phasenames[bus->phase],phasenames[newphase]);
|
| 418 | |
| 419 | bus->phase=newphase;
|
| 420 | bus->cmd_idx=0;
|
| 421 | bus->data_idx=0;
|
| 422 | |
| 423 | switch(bus->phase)
|
| 424 | {
|
| 425 | case SCSI_PHASE_BUS_FREE :
|
| 426 | scsi_out_line_change(device,SCSI_LINE_CD,1);
|
| 427 | scsi_out_line_change(device,SCSI_LINE_IO,1);
|
| 428 | scsi_out_line_change(device,SCSI_LINE_MSG,1);
|
| 429 | scsi_out_line_change(device,SCSI_LINE_REQ,1);
|
| 430 | scsi_out_line_change(device,SCSI_LINE_BSY,1);
|
| 431 | break;
|
| 432 | |
| 433 | case SCSI_PHASE_COMMAND :
|
| 434 | scsi_out_line_change(device,SCSI_LINE_CD,0);
|
| 435 | scsi_out_line_change(device,SCSI_LINE_IO,1);
|
| 436 | scsi_out_line_change(device,SCSI_LINE_MSG,1);
|
| 437 | scsi_out_line_change(device,SCSI_LINE_REQ,0);
|
| 438 | break;
|
| 439 | |
| 440 | case SCSI_PHASE_DATAOUT :
|
| 441 | scsi_out_line_change(device,SCSI_LINE_CD,1);
|
| 442 | scsi_out_line_change(device,SCSI_LINE_IO,1);
|
| 443 | scsi_out_line_change(device,SCSI_LINE_MSG,1);
|
| 444 | scsi_out_line_change(device,SCSI_LINE_REQ,0);
|
| 445 | break;
|
| 446 | |
| 447 | case SCSI_PHASE_DATAIN :
|
| 448 | scsi_out_line_change(device,SCSI_LINE_CD,1);
|
| 449 | scsi_out_line_change(device,SCSI_LINE_IO,0);
|
| 450 | scsi_out_line_change(device,SCSI_LINE_MSG,1);
|
| 451 | scsi_out_line_change(device,SCSI_LINE_REQ,0);
|
| 452 | break;
|
| 453 | |
| 454 | case SCSI_PHASE_STATUS : |
| 455 | scsi_out_line_change(device,SCSI_LINE_CD,0);
|
| 456 | scsi_out_line_change(device,SCSI_LINE_IO,0);
|
| 457 | scsi_out_line_change(device,SCSI_LINE_MSG,1);
|
| 458 | scsi_out_line_change(device,SCSI_LINE_REQ,0);
|
| 459 | break;
|
| 460 | |
| 461 | case SCSI_PHASE_MESSAGE_OUT : |
| 462 | scsi_out_line_change(device,SCSI_LINE_CD,0);
|
| 463 | scsi_out_line_change(device,SCSI_LINE_IO,1);
|
| 464 | scsi_out_line_change(device,SCSI_LINE_MSG,0);
|
| 465 | scsi_out_line_change(device,SCSI_LINE_REQ,0);
|
| 466 | break;
|
| 467 | |
| 468 | case SCSI_PHASE_MESSAGE_IN : |
| 469 | scsi_out_line_change(device,SCSI_LINE_CD,0);
|
| 470 | scsi_out_line_change(device,SCSI_LINE_IO,0);
|
| 471 | scsi_out_line_change(device,SCSI_LINE_MSG,0);
|
| 472 | scsi_out_line_change(device,SCSI_LINE_REQ,0);
|
| 473 | break;
|
| 474 | }
|
| 475 | }
|
| 476 | |
| 477 | UINT8 driveno(UINT8 drivesel)
|
| 478 | {
|
| 479 | switch (drivesel)
|
| 480 | {
|
| 481 | case 0x01 : return 0;
|
| 482 | case 0x02 : return 1;
|
| 483 | case 0x04 : return 2;
|
| 484 | case 0x08 : return 3;
|
| 485 | case 0x10 : return 4;
|
| 486 | case 0x20 : return 5;
|
| 487 | case 0x40 : return 6;
|
| 488 | case 0x80 : return 7;
|
| 489 | default : return 0;
|
| 490 | }
|
| 491 | }
|
| 492 | |
| 493 | // get the length of a SCSI command based on it's command byte type
|
| 494 | int get_scsi_cmd_len(int cbyte)
|
| 495 | {
|
| 496 | int group;
|
| 497 | |
| 498 | group = (cbyte>>5) & 7;
|
| 499 | |
| 500 | if (group == 0) return 6;
|
| 501 | if (group == 1 || group == 2) return 10;
|
| 502 | if (group == 5) return 12;
|
| 503 | |
| 504 | fatalerror("scsibus: Unknown SCSI command group %d\n", group);
|
| 505 | |
| 506 | return 6;
|
| 507 | }
|
| 508 | |
| 509 | void init_scsibus(const device_config *device)
|
| 510 | {
|
| 511 | scsibus_t *bus = get_token(device);
|
| 512 | const SCSIConfigTable *scsidevs = bus->interface->scsidevs;
|
| 513 | int devno;
|
| 514 | |
| 515 | if(!bus->initialised)
|
| 516 | {
|
| 517 | // try to open the devices
|
| 518 | for (devno = 0; devno < scsidevs->devs_present; devno++)
|
| 519 | {
|
| 520 | logerror("init_scsibus devno=%d \n",devno);
|
| 521 | SCSIAllocInstance( device->machine, scsidevs->devices[devno].scsiClass, &bus->devices[scsidevs->devices[devno].scsiID], scsidevs->devices[devno].diskregion );
|
| 522 | }
|
| 523 | |
| 524 | bus->initialised=1;
|
| 525 | }
|
| 526 | }
|
| 527 | |
| 528 | static DEVICE_START( scsibus )
|
| 529 | {
|
| 530 | scsibus_t *bus = get_token(device);
|
| 531 | |
| 532 | assert(device->static_config != NULL);
|
| 533 | bus->interface = device->static_config;
|
| 534 | |
| 535 | memset(bus->devices, 0, sizeof(bus->devices));
|
| 536 | |
| 537 | // Flag not initialised
|
| 538 | bus->initialised=0;
|
| 539 | |
| 540 | // All lines start high - inactive
|
| 541 | bus->linestate=0xFF; |
| 542 | |
| 543 | // Start with bus free
|
| 544 | bus->phase=SCSI_PHASE_BUS_FREE;
|
| 545 | |
| 546 | // Setup req/ack timers |
| 547 | bus->req_timer=timer_alloc(device->machine, req_timer_callback, (void *)device);
|
| 548 | bus->ack_timer=timer_alloc(device->machine, ack_timer_callback, (void *)device);
|
| 549 | |
| 550 | //timer_adjust_periodic(bus->reqack_timer, attotime_zero, 0, ATTOTIME_IN_MSEC(1));
|
| 551 | |
| 552 | bus->machine=device->machine;
|
| 553 | }
|
| 554 | |
| 555 | static DEVICE_STOP( scsibus )
|
| 556 | {
|
| 557 | scsibus_t *bus = get_token(device);
|
| 558 | int devno;
|
| 559 | |
| 560 | for (devno = 0; devno < bus->interface->scsidevs->devs_present; devno++)
|
| 561 | {
|
| 562 | SCSIDeleteInstance( bus->devices[devno] );
|
| 563 | }
|
| 564 | }
|
| 565 | |
| 566 | static DEVICE_RESET( scsibus )
|
| 567 | {
|
| 568 | }
|
| 569 | |
| 570 | DEVICE_GET_INFO( scsibus ) |
| 571 | {
|
| 572 | switch ( state ) |
| 573 | {
|
| 574 | /* --- the following bits of info are returned as 64-bit signed integers --- */
|
| 575 | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(scsibus_t); break;
|
| 576 | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
|
| 577 | case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_PERIPHERAL; break;
|
| 578 | |
| 579 | /* --- the following bits of info are returned as pointers to data or functions --- */
|
| 580 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(scsibus); break;
|
| 581 | case DEVINFO_FCT_STOP: info->stop = DEVICE_STOP_NAME(scsibus); break;
|
| 582 | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(scsibus); break;
|
| 583 | |
| 584 | /* --- the following bits of info are returned as NULL-terminated strings --- */
|
| 585 | case DEVINFO_STR_NAME: strcpy(info->s, "SCSI bus"); break;
|
| 586 | case DEVINFO_STR_FAMILY: strcpy(info->s, "SCSI"); break;
|
| 587 | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
|
| 588 | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
| 589 | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MAME and MESS Teams"); break;
|
| 590 | }
|
| 591 | }
|
src/mess/machine/rmnimbus.c
| r7051 | r7052 | |
| 21 | 21 | #include "machine/pic8259.h" |
| 22 | 22 | #include "machine/pit8253.h" |
| 23 | 23 | #include "machine/msm8251.h" |
| 24 | #include "machine/scsi.h" |
| 25 | #include "machine/scsibus.h" |
| 24 | 26 | #include "machine/z80sio.h" |
| 25 | 27 | #include "sound/ay8910.h" |
| 26 | 28 | #include "sound/msm5205.h" |
| r7051 | r7052 | |
| 38 | 40 | #define LOG_INTERRUPTS_EXT 1 |
| 39 | 41 | #define LOG_TIMER 0 |
| 40 | 42 | #define LOG_OPTIMIZATION 0 |
| 41 | | #define LOG_DMA |
| 43 | #define LOG_DMA 1 |
| 42 | 44 | #define CPU_RESUME_TRIGGER 7123 |
| 43 | 45 | #define LOG_KEYBOARD 0 |
| 44 | 46 | #define LOG_SIO 0 |
| 45 | | #define LOG_DISK 0 |
| 47 | #define LOG_DISK_FDD 0 |
| 48 | #define LOG_DISK_HDD 1 |
| 49 | #define LOG_DISK 1 |
| 46 | 50 | #define LOG_PC8031 0 |
| 47 | | #define LOG_PC8031_186 1 |
| 51 | #define LOG_PC8031_186 |
| 48 | 52 | #define LOG_PC8031_PORT 0 |
| 49 | | #define LOG_IOU 1 |
| 50 | | #define LOG_SOUND 1 |
| 53 | #define LOG_IOU 0 |
| 54 | #define LOG_SOUND 0 |
| 51 | 55 | |
| 52 | 56 | /* 80186 internal stuff */ |
| 53 | 57 | struct mem_state |
| r7051 | r7052 | |
| 140 | 144 | {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3} |
| 141 | 145 | }; |
| 142 | 146 | |
| 143 | | static struct _nimbus_fdc |
| 147 | |
| 148 | // Static data related to Floppy and SCSI hard disks |
| 149 | static struct _nimbus_drives |
| 144 | 150 | { |
| 145 | | UINT8 drq_enabled; |
| 146 | | UINT8 irq_enabled; |
| 147 | | UINT8 diskno; |
| 148 | | UINT8 motor_on; |
| 149 | | } nimbus_fdc; |
| 151 | UINT8 reg400; |
| 152 | UINT8 reg410_in; |
| 153 | UINT8 reg410_out; |
| 154 | UINT8 reg418; |
| 150 | 155 | |
| 156 | UINT8 drq_ff; |
| 157 | } nimbus_drives; |
| 151 | 158 | |
| 159 | |
| 160 | static const SCSIConfigTable SCSI_dev_table = |
| 161 | { |
| 162 | 1, /* 1 SCSI device */ |
| 163 | { |
| 164 | { SCSI_ID_0, HARDDISK0_TAG, SCSI_DEVICE_HARDDISK }, |
| 165 | } |
| 166 | }; |
| 167 | |
| 152 | 168 | /* 8031 Peripheral controler */ |
| 153 | 169 | |
| 154 | 170 | UINT8 pcregs[PC8031_RAMSIZE]; |
| r7051 | r7052 | |
| 177 | 193 | static void decode_dssi_f_plonk_char(const device_config *device,UINT16 ds, UINT16 si); |
| 178 | 194 | |
| 179 | 195 | static void fdc_reset(void); |
| 196 | static void generate_disk_int(running_machine *machine); |
| 197 | static void hdc_reset(running_machine *machine); |
| 198 | static void hdc_ctrl_write(running_machine *machine, UINT8 data); |
| 199 | static void hdc_post_rw(running_machine *machine); |
| 200 | static void hdc_drq(running_machine *machine); |
| 180 | 201 | |
| 181 | 202 | static void keyboard_reset(void); |
| 182 | 203 | static TIMER_CALLBACK(keyscan_callback); |
| r7051 | r7052 | |
| 318 | 339 | } |
| 319 | 340 | } |
| 320 | 341 | |
| 321 | | //logerror("Checking external ints\n"); |
| 322 | | /* check external interrupts */ |
| 342 | /* check external interrupts */ |
| 323 | 343 | for (IntNo = 0; IntNo < 4; IntNo++) |
| 324 | 344 | if ((i186.intr.ext[IntNo] & 0x0F) == Priority) |
| 325 | 345 | { |
| r7051 | r7052 | |
| 646 | 666 | int which = param; |
| 647 | 667 | struct dma_state *d = &i186.dma[which]; |
| 648 | 668 | |
| 649 | | /* force an update and see if we're really done */ |
| 650 | | //stream_update(dma_stream, 0); |
| 651 | | |
| 652 | 669 | /* complete the status update */ |
| 653 | 670 | d->control &= ~0x0002; |
| 654 | 671 | d->source += d->count; |
| r7051 | r7052 | |
| 700 | 717 | /* otherwise, set a timer */ |
| 701 | 718 | else |
| 702 | 719 | { |
| 703 | | // int count = d->count; |
| 704 | | |
| 705 | | /* adjust for redline racer */ |
| 706 | | // int dacnum = (d->dest & 0x3f) / 2; |
| 707 | | |
| 708 | 720 | if (LOG_DMA) logerror("Initiated DMA %d - count = %04X, source = %04X, dest = %04X\n", which, d->count, d->source, d->dest); |
| 709 | 721 | |
| 710 | 722 | d->finished = 0; |
| 711 | | /* timer_adjust_oneshot(d->finish_timer, |
| 712 | | ATTOTIME_IN_HZ(dac[dacnum].frequency) * (double)count, which);*/ |
| 713 | 723 | } |
| 714 | 724 | } |
| 715 | 725 | |
| r7051 | r7052 | |
| 974 | 984 | case 0x68: |
| 975 | 985 | if (LOG_PORTS) logerror("%05X:read 80186 DMA%d lower source address\n", cpu_get_pc(space->cpu), (offset - 0x60) / 8); |
| 976 | 986 | which = (offset - 0x60) / 8; |
| 977 | | // stream_update(dma_stream, 0); |
| 978 | 987 | return i186.dma[which].source; |
| 979 | 988 | |
| 980 | 989 | case 0x61: |
| 981 | 990 | case 0x69: |
| 982 | 991 | if (LOG_PORTS) logerror("%05X:read 80186 DMA%d upper source address\n", cpu_get_pc(space->cpu), (offset - 0x61) / 8); |
| 983 | 992 | which = (offset - 0x61) / 8; |
| 984 | | // stream_update(dma_stream, 0); |
| 985 | 993 | return i186.dma[which].source >> 16; |
| 986 | 994 | |
| 987 | 995 | case 0x62: |
| 988 | 996 | case 0x6a: |
| 989 | 997 | if (LOG_PORTS) logerror("%05X:read 80186 DMA%d lower dest address\n", cpu_get_pc(space->cpu), (offset - 0x62) / 8); |
| 990 | 998 | which = (offset - 0x62) / 8; |
| 991 | | // stream_update(dma_stream, 0); |
| 992 | 999 | return i186.dma[which].dest; |
| 993 | 1000 | |
| 994 | 1001 | case 0x63: |
| 995 | 1002 | case 0x6b: |
| 996 | 1003 | if (LOG_PORTS) logerror("%05X:read 80186 DMA%d upper dest address\n", cpu_get_pc(space->cpu), (offset - 0x63) / 8); |
| 997 | 1004 | which = (offset - 0x63) / 8; |
| 998 | | // stream_update(dma_stream, 0); |
| 999 | 1005 | return i186.dma[which].dest >> 16; |
| 1000 | 1006 | |
| 1001 | 1007 | case 0x64: |
| 1002 | 1008 | case 0x6c: |
| 1003 | 1009 | if (LOG_PORTS) logerror("%05X:read 80186 DMA%d transfer count\n", cpu_get_pc(space->cpu), (offset - 0x64) / 8); |
| 1004 | 1010 | which = (offset - 0x64) / 8; |
| 1005 | | // stream_update(dma_stream, 0); |
| 1006 | 1011 | return i186.dma[which].count; |
| 1007 | 1012 | |
| 1008 | 1013 | case 0x65: |
| 1009 | 1014 | case 0x6d: |
| 1010 | 1015 | if (LOG_PORTS) logerror("%05X:read 80186 DMA%d control\n", cpu_get_pc(space->cpu), (offset - 0x65) / 8); |
| 1011 | 1016 | which = (offset - 0x65) / 8; |
| 1012 | | // stream_update(dma_stream, 0); |
| 1013 | 1017 | return i186.dma[which].control; |
| 1014 | 1018 | |
| 1015 | 1019 | default: |
| r7051 | r7052 | |
| 1171 | 1175 | if (LOG_PORTS) logerror("%05X:80186 middle P chip select = %04X\n", cpu_get_pc(space->cpu), data16); |
| 1172 | 1176 | i186.mem.middle_size = data16 | 0x8038; |
| 1173 | 1177 | |
| 1174 | | temp = (i186.mem.peripheral & 0xffc0) << 4; |
| 1175 | | if (i186.mem.middle_size & 0x0040) |
| 1176 | | { |
| 1177 | | // install_mem_read_handler(2, temp, temp + 0x2ff, peripheral_r); |
| 1178 | | // install_mem_write_handler(2, temp, temp + 0x2ff, peripheral_w); |
| 1179 | | } |
| 1180 | | else |
| 1181 | | { |
| 1182 | | temp &= 0xffff; |
| 1183 | | // install_port_read_handler(2, temp, temp + 0x2ff, peripheral_r); |
| 1184 | | // install_port_write_handler(2, temp, temp + 0x2ff, peripheral_w); |
| 1185 | | } |
| 1186 | | |
| 1187 | 1178 | /* we need to do this at a time when the I86 context is swapped in */ |
| 1188 | 1179 | /* this register is generally set once at startup and never again, so it's a good */ |
| 1189 | 1180 | /* time to set it up */ |
| r7051 | r7052 | |
| 1194 | 1185 | case 0x68: |
| 1195 | 1186 | if (LOG_PORTS) logerror("%05X:80186 DMA%d lower source address = %04X\n", cpu_get_pc(space->cpu), (offset - 0x60) / 8, data16); |
| 1196 | 1187 | which = (offset - 0x60) / 8; |
| 1197 | | // stream_update(dma_stream, 0); |
| 1198 | 1188 | i186.dma[which].source = (i186.dma[which].source & ~0x0ffff) | (data16 & 0x0ffff); |
| 1199 | 1189 | break; |
| 1200 | 1190 | |
| r7051 | r7052 | |
| 1202 | 1192 | case 0x69: |
| 1203 | 1193 | if (LOG_PORTS) logerror("%05X:80186 DMA%d upper source address = %04X\n", cpu_get_pc(space->cpu), (offset - 0x61) / 8, data16); |
| 1204 | 1194 | which = (offset - 0x61) / 8; |
| 1205 | | // stream_update(dma_stream, 0); |
| 1206 | 1195 | i186.dma[which].source = (i186.dma[which].source & ~0xf0000) | ((data16 << 16) & 0xf0000); |
| 1207 | 1196 | break; |
| 1208 | 1197 | |
| r7051 | r7052 | |
| 1210 | 1199 | case 0x6a: |
| 1211 | 1200 | if (LOG_PORTS) logerror("%05X:80186 DMA%d lower dest address = %04X\n", cpu_get_pc(space->cpu), (offset - 0x62) / 8, data16); |
| 1212 | 1201 | which = (offset - 0x62) / 8; |
| 1213 | | // stream_update(dma_stream, 0); |
| 1214 | 1202 | i186.dma[which].dest = (i186.dma[which].dest & ~0x0ffff) | (data16 & 0x0ffff); |
| 1215 | 1203 | break; |
| 1216 | 1204 | |
| r7051 | r7052 | |
| 1218 | 1206 | case 0x6b: |
| 1219 | 1207 | if (LOG_PORTS) logerror("%05X:80186 DMA%d upper dest address = %04X\n", cpu_get_pc(space->cpu), (offset - 0x63) / 8, data16); |
| 1220 | 1208 | which = (offset - 0x63) / 8; |
| 1221 | | // stream_update(dma_stream, 0); |
| 1222 | 1209 | i186.dma[which].dest = (i186.dma[which].dest & ~0xf0000) | ((data16 << 16) & 0xf0000); |
| 1223 | 1210 | break; |
| 1224 | 1211 | |
| r7051 | r7052 | |
| 1226 | 1213 | case 0x6c: |
| 1227 | 1214 | if (LOG_PORTS) logerror("%05X:80186 DMA%d transfer count = %04X\n", cpu_get_pc(space->cpu), (offset - 0x64) / 8, data16); |
| 1228 | 1215 | which = (offset - 0x64) / 8; |
| 1229 | | // stream_update(dma_stream, 0); |
| 1230 | 1216 | i186.dma[which].count = data16; |
| 1231 | 1217 | break; |
| 1232 | 1218 | |
| r7051 | r7052 | |
| 1234 | 1220 | case 0x6d: |
| 1235 | 1221 | if (LOG_PORTS) logerror("%05X:80186 DMA%d control = %04X\n", cpu_get_pc(space->cpu), (offset - 0x65) / 8, data16); |
| 1236 | 1222 | which = (offset - 0x65) / 8; |
| 1237 | | // stream_update(dma_stream, 0); |
| 1238 | 1223 | update_dma_control(space->machine, which, data16); |
| 1239 | 1224 | break; |
| 1240 | 1225 | |
| r7051 | r7052 | |
| 1256 | 1241 | memory_install_read16_handler(cputag_get_address_space(space->machine, MAINCPU_TAG, ADDRESS_SPACE_IO), temp, temp + 0xff, 0, 0, i186_internal_port_r); |
| 1257 | 1242 | memory_install_write16_handler(cputag_get_address_space(space->machine, MAINCPU_TAG, ADDRESS_SPACE_IO), temp, temp + 0xff, 0, 0, i186_internal_port_w); |
| 1258 | 1243 | } |
| 1259 | | /* popmessage("Sound CPU reset");*/ |
| 1260 | 1244 | break; |
| 1261 | 1245 | |
| 1262 | 1246 | default: |
| r7051 | r7052 | |
| 1271 | 1255 | nimbus_cpu_reset(machine); |
| 1272 | 1256 | iou_reset(); |
| 1273 | 1257 | fdc_reset(); |
| 1258 | hdc_reset(machine); |
| 1274 | 1259 | keyboard_reset(); |
| 1275 | 1260 | pc8031_reset(); |
| 1276 | 1261 | sound_reset(machine); |
| r7051 | r7052 | |
| 1973 | 1958 | |
| 1974 | 1959 | static void fdc_reset(void) |
| 1975 | 1960 | { |
| 1976 | | nimbus_fdc.irq_enabled=0; |
| 1977 | | nimbus_fdc.drq_enabled=0; |
| 1978 | | nimbus_fdc.diskno=0; |
| 1979 | | nimbus_fdc.motor_on=0; |
| 1961 | nimbus_drives.reg400=0; |
| 1962 | nimbus_drives.reg410_in=0; |
| 1963 | nimbus_drives.reg410_out=0; |
| 1980 | 1964 | } |
| 1981 | 1965 | |
| 1982 | | static WRITE_LINE_DEVICE_HANDLER( nimbus_fdc_intrq_w ) |
| 1966 | static void generate_disk_int(running_machine *machine) |
| 1983 | 1967 | { |
| 1984 | 1968 | if(LOG_DISK) |
| 1985 | | logerror("nimbus_fdc_intrq_w(%d)\n", state); |
| 1969 | logerror("nimbus_drives_intrq\n"); |
| 1986 | 1970 | |
| 1987 | | if(state && (iou_reg092 & FDC_INT_ENABLE)) |
| 1971 | if(iou_reg092 & DISK_INT_ENABLE) |
| 1988 | 1972 | { |
| 1989 | | external_int(device->machine,0,EXTERNAL_INT_FDC); |
| 1973 | external_int(machine,0,EXTERNAL_INT_DISK); |
| 1990 | 1974 | } |
| 1991 | 1975 | } |
| 1992 | 1976 | |
| 1977 | static WRITE_LINE_DEVICE_HANDLER( nimbus_fdc_intrq_w ) |
| 1978 | { |
| 1979 | if (state) |
| 1980 | generate_disk_int(device->machine); |
| 1981 | } |
| 1982 | |
| 1993 | 1983 | static WRITE_LINE_DEVICE_HANDLER( nimbus_fdc_drq_w ) |
| 1994 | 1984 | { |
| 1995 | 1985 | |
| 1996 | 1986 | if(LOG_DISK) |
| 1997 | | logerror("nimbus_fdc_drq_w(%d)\n", state); |
| 1987 | logerror("nimbus_drives_drq_w(%d)\n", state); |
| 1998 | 1988 | |
| 1999 | | if(state && nimbus_fdc.drq_enabled) |
| 1989 | if(state && FDC_DRQ_ENABLED()) |
| 2000 | 1990 | drq_callback(device->machine,1); |
| 2001 | 1991 | } |
| 2002 | 1992 | |
| 2003 | | READ8_HANDLER( nimbus_fdc_r ) |
| 1993 | /* |
| 1994 | 0x410 read bits |
| 1995 | |
| 1996 | 0 Ready from floppy |
| 1997 | 1 Index pulse from floppy |
| 1998 | 2 Motor on from floppy |
| 1999 | 3 MSG from HDD |
| 2000 | 4 !BSY from HDD |
| 2001 | 5 !I/O from HDD |
| 2002 | 6 !C/D |
| 2003 | 7 !REQ from HDD |
| 2004 | */ |
| 2005 | |
| 2006 | READ8_HANDLER( nimbus_disk_r ) |
| 2004 | 2007 | { |
| 2005 | 2008 | int result = 0; |
| 2006 | 2009 | const device_config *fdc = devtag_get_device(space->machine, FDC_TAG); |
| 2010 | const device_config *hdc = devtag_get_device(space->machine, SCSIBUS_TAG); |
| 2011 | |
| 2007 | 2012 | int pc=cpu_get_pc(space->cpu); |
| 2008 | | const device_config *drive = devtag_get_device(space->machine, nimbus_wd17xx_interface.floppy_drive_tags[nimbus_fdc.diskno]); |
| 2013 | const device_config *drive = devtag_get_device(space->machine, nimbus_wd17xx_interface.floppy_drive_tags[FDC_DRIVE()]); |
| 2009 | 2014 | |
| 2010 | 2015 | switch(offset*2) |
| 2011 | 2016 | { |
| 2012 | 2017 | case 0x08 : |
| 2013 | 2018 | result = wd17xx_status_r(fdc, 0); |
| 2014 | | if (LOG_DISK) logerror("Disk status=%2.2X\n",result); |
| 2019 | if (LOG_DISK_FDD) logerror("Disk status=%2.2X\n",result); |
| 2015 | 2020 | break; |
| 2016 | 2021 | case 0x0A : |
| 2017 | 2022 | result = wd17xx_track_r(fdc, 0); |
| r7051 | r7052 | |
| 2023 | 2028 | result = wd17xx_data_r(fdc, 0); |
| 2024 | 2029 | break; |
| 2025 | 2030 | case 0x10 : |
| 2026 | | result = (nimbus_fdc.motor_on ? 0x04 : 0x00) | |
| 2027 | | (floppy_drive_get_flag_state(drive, FLOPPY_DRIVE_INDEX) ? 0x00 : 0x02) | |
| 2028 | | (floppy_drive_get_flag_state(drive, FLOPPY_DRIVE_READY) ? 0x01 : 0x00); |
| 2031 | nimbus_drives.reg410_in &= ~FDC_BITS_410; |
| 2032 | nimbus_drives.reg410_in |= (FDC_MOTOR() ? FDC_MOTOR_MASKI : 0x00); |
| 2033 | nimbus_drives.reg410_in |= (floppy_drive_get_flag_state(drive, FLOPPY_DRIVE_INDEX) ? 0x00 : FDC_INDEX_MASK); |
| 2034 | nimbus_drives.reg410_in |= (floppy_drive_get_flag_state(drive, FLOPPY_DRIVE_READY) ? FDC_READY_MASK : 0x00); |
| 2035 | |
| 2036 | // Flip inverted bits |
| 2037 | result=nimbus_drives.reg410_in ^ INV_BITS_410; |
| 2029 | 2038 | break; |
| 2039 | case 0x18 : |
| 2040 | result = scsi_data_r(hdc); |
| 2041 | hdc_post_rw(space->machine); |
| 2030 | 2042 | default: |
| 2031 | 2043 | break; |
| 2032 | 2044 | } |
| 2033 | 2045 | |
| 2034 | | if(LOG_DISK) |
| 2046 | if(LOG_DISK_FDD) |
| 2035 | 2047 | logerror("Nimbus FDCR at pc=%08X from %04X data=%02X\n",pc,(offset*2)+0x400,result); |
| 2036 | 2048 | |
| 2049 | if((LOG_DISK_HDD) && ((offset*2)>=0x10)) |
| 2050 | logerror("Nimbus HDCR at pc=%08X from %04X data=%02X\n",pc,(offset*2)+0x400,result); |
| 2051 | |
| 2052 | |
| 2037 | 2053 | return result; |
| 2038 | 2054 | } |
| 2039 | 2055 | |
| 2040 | | WRITE8_HANDLER( nimbus_fdc_w ) |
| 2056 | /* |
| 2057 | 0x400 write bits |
| 2058 | |
| 2059 | 0 drive 0 select |
| 2060 | 1 drive 1 select |
| 2061 | 2 drive 2 select |
| 2062 | 3 drive 3 select |
| 2063 | 4 side select |
| 2064 | 5 fdc motor on |
| 2065 | 6 hdc drq enabled |
| 2066 | 7 fdc drq enabled |
| 2067 | |
| 2068 | 0x410 write bits |
| 2069 | |
| 2070 | 0 SCSI reset |
| 2071 | 1 SCSI SEL |
| 2072 | 2 SCSI IRQ Enable |
| 2073 | */ |
| 2074 | |
| 2075 | WRITE8_HANDLER( nimbus_disk_w ) |
| 2041 | 2076 | { |
| 2042 | 2077 | const device_config *fdc = devtag_get_device(space->machine, FDC_TAG); |
| 2043 | | int pc=cpu_get_pc(space->cpu); |
| 2078 | const device_config *hdc = devtag_get_device(space->machine, SCSIBUS_TAG); |
| 2079 | int pc=cpu_get_pc(space->cpu); |
| 2080 | UINT8 reg400_old = nimbus_drives.reg400; |
| 2081 | |
| 2082 | if(LOG_DISK_FDD) |
| 2083 | logerror("Nimbus FDCW at %05X write of %02X to %04X\n",pc,data,(offset*2)+0x400); |
| 2044 | 2084 | |
| 2045 | | if(LOG_DISK) |
| 2046 | | logerror("Nimbus FDCW at %08X write of %02X to %04X\n",pc,data,(offset*2)+0x400); |
| 2085 | if((LOG_DISK_HDD) && (((offset*2)>=0x10) || (offset==0))) |
| 2086 | logerror("Nimbus HDCW at %05X write of %02X to %04X\n",pc,data,(offset*2)+0x400); |
| 2047 | 2087 | |
| 2048 | 2088 | switch(offset*2) |
| 2049 | 2089 | { |
| 2050 | 2090 | case 0x00 : |
| 2051 | | switch (data & 0x0F) |
| 2052 | | { |
| 2053 | | case 0x01 : nimbus_fdc.diskno=0; break; |
| 2054 | | case 0x02 : nimbus_fdc.diskno=1; break; |
| 2055 | | case 0x04 : nimbus_fdc.diskno=2; break; |
| 2056 | | case 0x08 : nimbus_fdc.diskno=3; break; |
| 2057 | | //default : nimbus_fdc.diskno=NO_DRIVE_SELECTED; break; // no drive selected |
| 2058 | | } |
| 2059 | | if (nimbus_fdc.diskno!=NO_DRIVE_SELECTED) |
| 2060 | | { |
| 2061 | | wd17xx_set_drive(fdc, nimbus_fdc.diskno); |
| 2062 | | wd17xx_set_side(fdc, (data & 0x10) ? 1 : 0); |
| 2063 | | } |
| 2064 | | nimbus_fdc.motor_on=(data & 0x20); |
| 2065 | | nimbus_fdc.drq_enabled=(data & 0x80); |
| 2066 | | nimbus_fdc.irq_enabled=1; |
| 2091 | nimbus_drives.reg400=data; |
| 2092 | |
| 2093 | wd17xx_set_drive(fdc,FDC_DRIVE()); |
| 2094 | wd17xx_set_side(fdc, FDC_SIDE()); |
| 2067 | 2095 | |
| 2068 | 2096 | // Nimbus FDC is hard wired for double density |
| 2069 | 2097 | wd17xx_set_density(fdc, DEN_MFM_LO); |
| 2070 | | break; |
| 2098 | |
| 2099 | //logerror("nimbus_drives.reg400=%02X, data=%02X, drq_ff=%d\n",reg400_old,data,nimbus_drives.drq_ff); |
| 2100 | |
| 2101 | // if we enable hdc drq with a pending condition, act on it |
| 2102 | if((data & HDC_DRQ_MASK) && (~reg400_old & HDC_DRQ_MASK)) |
| 2103 | hdc_drq(space->machine); |
| 2104 | |
| 2105 | break; |
| 2071 | 2106 | case 0x08 : |
| 2072 | 2107 | wd17xx_command_w(fdc, 0, data); |
| 2073 | 2108 | break; |
| r7051 | r7052 | |
| 2080 | 2115 | case 0x0E : |
| 2081 | 2116 | wd17xx_data_w(fdc, 0, data); |
| 2082 | 2117 | break; |
| 2118 | case 0x10 : |
| 2119 | hdc_ctrl_write(space->machine,data); |
| 2120 | break; |
| 2121 | |
| 2122 | case 0x18 : |
| 2123 | scsi_data_w(hdc, data); |
| 2124 | hdc_post_rw(space->machine); |
| 2125 | break; |
| 2083 | 2126 | } |
| 2084 | 2127 | } |
| 2085 | 2128 | |
| 2129 | static void hdc_reset(running_machine *machine) |
| 2130 | { |
| 2131 | const device_config *hdc = devtag_get_device(machine, SCSIBUS_TAG); |
| 2132 | |
| 2133 | init_scsibus(hdc); |
| 2134 | |
| 2135 | nimbus_drives.reg410_in=0; |
| 2136 | nimbus_drives.reg410_in |= (get_scsi_line(hdc,SCSI_LINE_REQ) ? HDC_REQ_MASK : 0); |
| 2137 | nimbus_drives.reg410_in |= (get_scsi_line(hdc,SCSI_LINE_CD) ? HDC_CD_MASK : 0); |
| 2138 | nimbus_drives.reg410_in |= (get_scsi_line(hdc,SCSI_LINE_IO) ? HDC_IO_MASK : 0); |
| 2139 | nimbus_drives.reg410_in |= (get_scsi_line(hdc,SCSI_LINE_BSY) ? HDC_BSY_MASK : 0); |
| 2140 | nimbus_drives.reg410_in |= (get_scsi_line(hdc,SCSI_LINE_MSG) ? HDC_MSG_MASK : 0); |
| 2141 | |
| 2142 | nimbus_drives.drq_ff=0; |
| 2143 | } |
| 2144 | |
| 2145 | static void hdc_ctrl_write(running_machine *machine, UINT8 data) |
| 2146 | { |
| 2147 | const device_config *hdc = devtag_get_device(machine, SCSIBUS_TAG); |
| 2148 | |
| 2149 | // If we enable the HDC interupt, and an interrupt is pending, go deal with it. |
| 2150 | if(((data & HDC_IRQ_MASK) && (~nimbus_drives.reg410_out & HDC_IRQ_MASK)) && |
| 2151 | ((~nimbus_drives.reg410_in & HDC_INT_TRIGGER)==HDC_INT_TRIGGER)) |
| 2152 | generate_disk_int(machine); |
| 2153 | |
| 2154 | nimbus_drives.reg410_out=data; |
| 2155 | |
| 2156 | set_scsi_line(hdc, SCSI_LINE_RESET, (data & HDC_RESET_MASK) ? 0 : 1); |
| 2157 | set_scsi_line(hdc, SCSI_LINE_SEL, (data & HDC_SEL_MASK) ? 0 : 1); |
| 2158 | } |
| 2159 | |
| 2160 | static void hdc_post_rw(running_machine *machine) |
| 2161 | { |
| 2162 | const device_config *hdc = devtag_get_device(machine, SCSIBUS_TAG); |
| 2163 | |
| 2164 | if((nimbus_drives.reg410_in & HDC_REQ_MASK)==0) |
| 2165 | set_scsi_line(hdc,SCSI_LINE_ACK,0); |
| 2166 | } |
| 2167 | |
| 2168 | static void hdc_drq(running_machine *machine) |
| 2169 | { |
| 2170 | if(HDC_DRQ_ENABLED() && nimbus_drives.drq_ff) |
| 2171 | { |
| 2172 | drq_callback(machine,1); |
| 2173 | nimbus_drives.drq_ff=0; |
| 2174 | } |
| 2175 | } |
| 2176 | |
| 2177 | void nimbus_scsi_linechange(const device_config *device, UINT8 line, UINT8 state) |
| 2178 | { |
| 2179 | UINT8 mask = 0; |
| 2180 | |
| 2181 | switch (line) |
| 2182 | { |
| 2183 | case SCSI_LINE_REQ : mask=HDC_REQ_MASK; break; |
| 2184 | case SCSI_LINE_CD : mask=HDC_CD_MASK; break; |
| 2185 | case SCSI_LINE_IO : mask=HDC_IO_MASK; break; |
| 2186 | case SCSI_LINE_BSY : mask=HDC_BSY_MASK; break; |
| 2187 | case SCSI_LINE_MSG : mask=HDC_MSG_MASK; break; |
| 2188 | } |
| 2189 | |
| 2190 | if(state) |
| 2191 | nimbus_drives.reg410_in|=mask; |
| 2192 | else |
| 2193 | nimbus_drives.reg410_in&=~mask; |
| 2194 | |
| 2195 | |
| 2196 | if(line==SCSI_LINE_REQ) |
| 2197 | { |
| 2198 | //logerror("nimbus_scsi_linechange(%02X,%d), ~nimbus_drives.reg410_in=%02X, mask=%02X, (~reg410 & mask)=%02X, int_enabled=%d, int_enabled=%d\n", |
| 2199 | // line,state,~nimbus_drives.reg410_in,HDC_INT_TRIGGER,(~nimbus_drives.reg410_in & HDC_INT_TRIGGER),HDC_IRQ_ENABLED(),HDC_DRQ_ENABLED()); |
| 2200 | if (state==0) |
| 2201 | { |
| 2202 | if(HDC_IRQ_ENABLED() && ((~nimbus_drives.reg410_in & HDC_INT_TRIGGER)==HDC_INT_TRIGGER)) |
| 2203 | generate_disk_int(device->machine); |
| 2204 | |
| 2205 | if((nimbus_drives.reg410_in & HDC_CD_MASK)==HDC_CD_MASK) |
| 2206 | { |
| 2207 | nimbus_drives.drq_ff=1; |
| 2208 | hdc_drq(device->machine); |
| 2209 | } |
| 2210 | } |
| 2211 | else |
| 2212 | set_scsi_line(device,SCSI_LINE_ACK,1); |
| 2213 | } |
| 2214 | } |
| 2215 | |
| 2086 | 2216 | /* 8031/8051 Peripheral controler 80186 side */ |
| 2087 | 2217 | |
| 2088 | 2218 | #define REG_0C2_INIT 1 |
| r7051 | r7052 | |
| 2136 | 2266 | if(LOG_PC8031_186) |
| 2137 | 2267 | logerror("Nimbus PCIOR %08X read of %04X returns %02X reg0C2_ptr=%02X\n",pc,(offset*2)+0xC0,result,reg0C2_ptr); |
| 2138 | 2268 | |
| 2139 | | dump_pcregs(); |
| 2269 | if(LOG_PC8031_186) |
| 2270 | dump_pcregs(); |
| 2140 | 2271 | |
| 2141 | 2272 | return result; |
| 2142 | 2273 | } |