From 645ed3fdcdd2c2af594fc28a3ece38236a363580 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 5 Dec 2020 09:33:07 +0100 Subject: [PATCH] The NCR 5380 bus state machine now uses a switch block. --- src/scsi/scsi_ncr5380.c | 296 +++++++++++++++++++++------------------- 1 file changed, 153 insertions(+), 143 deletions(-) diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 29cfe7f35..50dee9d40 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -376,167 +376,176 @@ ncr_bus_update(void *priv, int bus) if (bus & BUS_ARB) ncr->state = STATE_IDLE; - if (ncr->state == STATE_IDLE) { - ncr->clear_req = ncr->wait_data = ncr->wait_complete = 0; - if ((bus & BUS_SEL) && !(bus & BUS_BSY)) { - ncr_log("Selection phase\n"); - sel_data = BUS_GETDATA(bus); + switch (ncr->state) { + case STATE_IDLE: + ncr->clear_req = ncr->wait_data = ncr->wait_complete = 0; + if ((bus & BUS_SEL) && !(bus & BUS_BSY)) { + ncr_log("Selection phase\n"); + sel_data = BUS_GETDATA(bus); - ncr->target_id = get_dev_id(sel_data); + ncr->target_id = get_dev_id(sel_data); - ncr_log("Select - target ID = %i\n", ncr->target_id); + ncr_log("Select - target ID = %i\n", ncr->target_id); - /*Once the device has been found and selected, mark it as busy*/ - if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr->target_id])) { - ncr->cur_bus |= BUS_BSY; - ncr->state = STATE_SELECT; - } else { - ncr_log("Device not found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); - ncr->cur_bus = 0; - } - } - } else if (ncr->state == STATE_SELECT) { - if (!(bus & BUS_SEL)) { - if (!(bus & BUS_ATN)) { + /*Once the device has been found and selected, mark it as busy*/ if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr->target_id])) { - ncr_log("Device found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); - ncr->state = STATE_COMMAND; - ncr->cur_bus = BUS_BSY | BUS_REQ; - ncr_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); - ncr->command_pos = 0; - SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); - picint(1 << ncr_dev->irq); + ncr->cur_bus |= BUS_BSY; + ncr->state = STATE_SELECT; } else { - ncr->state = STATE_IDLE; + ncr_log("Device not found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); ncr->cur_bus = 0; } - } else { - ncr_log("Set to SCSI Message Out\n"); - ncr->new_phase = SCSI_PHASE_MESSAGE_OUT; - ncr->wait_data = 4; - ncr->msgout_pos = 0; - ncr->is_msgout = 1; } - } - } else if (ncr->state == STATE_COMMAND) { - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - /*Write command byte to the output data register*/ - ncr->command[ncr->command_pos++] = BUS_GETDATA(bus); - ncr->clear_req = 3; - ncr->new_phase = ncr->cur_bus & SCSI_PHASE_MESSAGE_IN; - ncr->cur_bus &= ~BUS_REQ; - - ncr_log("Command pos=%i, output data=%02x\n", ncr->command_pos, BUS_GETDATA(bus)); - - if (ncr->command_pos == cmd_len[(ncr->command[0] >> 5) & 7]) { - if (ncr->is_msgout) { - ncr->is_msgout = 0; - ncr->command[1] &= ~(0x80 | 0x40 | 0x20); - ncr->command[1] |= ncr->msglun << 5; - } - - /*Reset data position to default*/ - ncr->data_pos = 0; - - dev = &scsi_devices[ncr->target_id]; - - ncr_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->status); - dev->buffer_length = -1; - scsi_device_command_phase0(dev, ncr->command); - ncr_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->buffer_length, dev->phase); - - ncr_dev->period = 1.0; /* 1 us default */ - ncr->wait_data = 4; - ncr->data_wait = 0; - - if (dev->status == SCSI_STATUS_OK) { - /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ - if (dev->buffer_length && (dev->phase == SCSI_PHASE_DATA_IN || dev->phase == SCSI_PHASE_DATA_OUT)) { - p = scsi_device_get_callback(dev); - if (p <= 0.0) - ncr_dev->period = 0.2/* * ((double) dev->buffer_length) */; - else - ncr_dev->period = p / ((double) dev->buffer_length); - ncr->data_wait |= 2; + break; + case STATE_SELECT: + if (!(bus & BUS_SEL)) { + if (!(bus & BUS_ATN)) { + if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr->target_id])) { + ncr_log("Device found at ID %i, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); + ncr->state = STATE_COMMAND; + ncr->cur_bus = BUS_BSY | BUS_REQ; + ncr_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); + ncr->command_pos = 0; + SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); + picint(1 << ncr_dev->irq); + } else { + ncr->state = STATE_IDLE; + ncr->cur_bus = 0; } + } else { + ncr_log("Set to SCSI Message Out\n"); + ncr->new_phase = SCSI_PHASE_MESSAGE_OUT; + ncr->wait_data = 4; + ncr->msgout_pos = 0; + ncr->is_msgout = 1; } - - ncr->new_phase = dev->phase; } - } - } else if (ncr->state == STATE_DATAIN) { - dev = &scsi_devices[ncr->target_id]; - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - if (ncr->data_pos >= dev->buffer_length) { + break; + case STATE_COMMAND: + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + /*Write command byte to the output data register*/ + ncr->command[ncr->command_pos++] = BUS_GETDATA(bus); + ncr->clear_req = 3; + ncr->new_phase = ncr->cur_bus & SCSI_PHASE_MESSAGE_IN; ncr->cur_bus &= ~BUS_REQ; - scsi_device_command_phase1(dev); - ncr->new_phase = SCSI_PHASE_STATUS; + + ncr_log("Command pos=%i, output data=%02x\n", ncr->command_pos, BUS_GETDATA(bus)); + + if (ncr->command_pos == cmd_len[(ncr->command[0] >> 5) & 7]) { + if (ncr->is_msgout) { + ncr->is_msgout = 0; + ncr->command[1] &= ~(0x80 | 0x40 | 0x20); + ncr->command[1] |= ncr->msglun << 5; + } + + /*Reset data position to default*/ + ncr->data_pos = 0; + + dev = &scsi_devices[ncr->target_id]; + + ncr_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->status); + dev->buffer_length = -1; + scsi_device_command_phase0(dev, ncr->command); + ncr_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->buffer_length, dev->phase); + + ncr_dev->period = 1.0; /* 1 us default */ + ncr->wait_data = 4; + ncr->data_wait = 0; + + if (dev->status == SCSI_STATUS_OK) { + /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ + if (dev->buffer_length && (dev->phase == SCSI_PHASE_DATA_IN || dev->phase == SCSI_PHASE_DATA_OUT)) { + p = scsi_device_get_callback(dev); + if (p <= 0.0) + ncr_dev->period = 0.2/* * ((double) dev->buffer_length) */; + else + ncr_dev->period = p / ((double) dev->buffer_length); + ncr->data_wait |= 2; + } + } + + ncr->new_phase = dev->phase; + } + } + break; + case STATE_DATAIN: + dev = &scsi_devices[ncr->target_id]; + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + if (ncr->data_pos >= dev->buffer_length) { + ncr->cur_bus &= ~BUS_REQ; + scsi_device_command_phase1(dev); + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } else { + ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; + if (ncr->data_wait & 2) + ncr->data_wait &= ~2; + if (ncr->dma_mode == DMA_IDLE) { + ncr->data_wait |= 1; + wait_timer_on(ncr_dev); + } else + ncr->clear_req = 3; + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_DATA_IN; + } + } + break; + case STATE_DATAOUT: + dev = &scsi_devices[ncr->target_id]; + + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus); + + if (ncr->data_pos >= dev->buffer_length) { + ncr->cur_bus &= ~BUS_REQ; + scsi_device_command_phase1(dev); + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } else { + /*More data is to be transferred, place a request*/ + if (ncr->dma_mode == DMA_IDLE) { + ncr->data_wait |= 1; + wait_timer_on(ncr_dev); + } else + ncr->clear_req = 3; + ncr->cur_bus &= ~BUS_REQ; + ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); + } + } + break; + case STATE_STATUS: + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + /*All transfers done, wait until next transfer*/ + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_MESSAGE_IN; ncr->wait_data = 4; - ncr->wait_complete = 8; - } else { - ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; - if (ncr->data_wait & 2) - ncr->data_wait &= ~2; - if (ncr->dma_mode == DMA_IDLE) { - ncr->data_wait |= 1; - wait_timer_on(ncr_dev); - } else - ncr->clear_req = 3; - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_DATA_IN; + ncr->wait_complete = 8; } - } - } else if (ncr->state == STATE_DATAOUT) { - dev = &scsi_devices[ncr->target_id]; - - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus); - - if (ncr->data_pos >= dev->buffer_length) { + break; + case STATE_MESSAGEIN: + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { ncr->cur_bus &= ~BUS_REQ; - scsi_device_command_phase1(dev); - ncr->new_phase = SCSI_PHASE_STATUS; + ncr->new_phase = BUS_IDLE; ncr->wait_data = 4; - ncr->wait_complete = 8; - } else { - /*More data is to be transferred, place a request*/ - if (ncr->dma_mode == DMA_IDLE) { - ncr->data_wait |= 1; - wait_timer_on(ncr_dev); - } else - ncr->clear_req = 3; - ncr->cur_bus &= ~BUS_REQ; - ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); } - } - } else if (ncr->state == STATE_STATUS) { - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - /*All transfers done, wait until next transfer*/ - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = SCSI_PHASE_MESSAGE_IN; - ncr->wait_data = 4; - ncr->wait_complete = 8; - } - } else if (ncr->state == STATE_MESSAGEIN) { - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - ncr->cur_bus &= ~BUS_REQ; - ncr->new_phase = BUS_IDLE; - ncr->wait_data = 4; - } - } else if (ncr->state == STATE_MESSAGEOUT) { - ncr_log("Ack on MSGOUT = %02x\n", (bus & BUS_ACK)); - if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - ncr->msgout[ncr->msgout_pos++] = BUS_GETDATA(bus); - msglen = getmsglen(ncr->msgout, ncr->msgout_pos); - if (ncr->msgout_pos >= msglen) { - if ((ncr->msgout[0] & (0x80 | 0x20)) == 0x80) + break; + case STATE_MESSAGEOUT: + ncr_log("Ack on MSGOUT = %02x\n", (bus & BUS_ACK)); + if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { + ncr->msgout[ncr->msgout_pos++] = BUS_GETDATA(bus); + msglen = getmsglen(ncr->msgout, ncr->msgout_pos); + if (ncr->msgout_pos >= msglen) { + if ((ncr->msgout[0] & (0x80 | 0x20)) == 0x80) ncr->msglun = ncr->msgout[0] & 7; - ncr->cur_bus &= ~BUS_REQ; - ncr->state = STATE_MESSAGE_ID; + ncr->cur_bus &= ~BUS_REQ; + ncr->state = STATE_MESSAGE_ID; + } } - } - } else if (ncr->state == STATE_MESSAGE_ID) { + break; + case STATE_MESSAGE_ID: if ((ncr->target_id != (uint8_t)-1) && scsi_device_present(&scsi_devices[ncr->target_id])) { ncr_log("Device found at ID %i on MSGOUT, Current Bus BSY=%02x\n", ncr->target_id, ncr->cur_bus); ncr->state = STATE_COMMAND; @@ -545,7 +554,8 @@ ncr_bus_update(void *priv, int bus) ncr->command_pos = 0; SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); } - } + break; + } ncr->bus_in = bus; }