sc53c94: refactor state machine.

This commit is contained in:
Maxim Poliakovski 2022-11-07 12:28:30 +01:00
parent 40a02cc0f7
commit ca5f81417f
2 changed files with 75 additions and 45 deletions

View File

@ -267,9 +267,6 @@ void Sc53C94::exec_command()
exec_next_command(); exec_next_command();
break; break;
case CMD_XFER: case CMD_XFER:
static SeqDesc * xfer_desc = new SeqDesc[3]{
{SeqState::IDLE, 0, INTSTAT_SR}
};
if (!this->is_initiator) { if (!this->is_initiator) {
// clear command FIFO // clear command FIFO
this->cmd_fifo_pos = 0; this->cmd_fifo_pos = 0;
@ -277,23 +274,23 @@ void Sc53C94::exec_command()
this->update_irq(); this->update_irq();
} else { } else {
this->seq_step = 0; this->seq_step = 0;
this->cmd_steps = xfer_desc; this->cmd_steps = nullptr;
this->cur_state = SeqState::XFER_BEGIN; this->cur_state = SeqState::XFER_BEGIN;
this->sequencer(); this->sequencer();
} }
break; break;
case CMD_COMPLETE_STEPS: case CMD_COMPLETE_STEPS:
static SeqDesc * complete_steps_desc = new SeqDesc[3]{ static SeqDesc * complete_steps_desc = new SeqDesc[3]{
{SeqState::RCV_MESSAGE, 0, 0}, {SeqState::RCV_STATUS, 0, 0},
{SeqState::XFER_END, 0, 0}, {SeqState::RCV_MESSAGE, 0, 0},
{SeqState::IDLE, 0, INTSTAT_SR} {SeqState::CMD_COMPLETE, 0, INTSTAT_SR}
}; };
if (this->bus_obj->current_phase() != ScsiPhase::STATUS) { if (this->bus_obj->current_phase() != ScsiPhase::STATUS) {
ABORT_F("Sc53C94: complete steps only works in the STATUS phase"); ABORT_F("Sc53C94: complete steps only works in the STATUS phase");
} }
this->seq_step = 0; this->seq_step = 0;
this->cmd_steps = complete_steps_desc; this->cmd_steps = complete_steps_desc;
this->cur_state = SeqState::RCV_STATUS; this->cur_state = this->cmd_steps->next_step;
this->sequencer(); this->sequencer();
break; break;
case CMD_MSG_ACCEPTED: case CMD_MSG_ACCEPTED:
@ -309,7 +306,7 @@ void Sc53C94::exec_command()
case CMD_SELECT_NO_ATN: case CMD_SELECT_NO_ATN:
static SeqDesc * sel_no_atn_desc = new SeqDesc[3]{ static SeqDesc * sel_no_atn_desc = new SeqDesc[3]{
{SeqState::SEL_BEGIN, 0, INTSTAT_DIS }, {SeqState::SEL_BEGIN, 0, INTSTAT_DIS },
{SeqState::CMD_BEGIN, 3, INTSTAT_SR | INTSTAT_SO}, {SeqState::SEND_CMD, 3, INTSTAT_SR | INTSTAT_SO},
{SeqState::CMD_COMPLETE, 4, INTSTAT_SR | INTSTAT_SO}, {SeqState::CMD_COMPLETE, 4, INTSTAT_SR | INTSTAT_SO},
}; };
this->seq_step = 0; this->seq_step = 0;
@ -318,6 +315,20 @@ void Sc53C94::exec_command()
this->sequencer(); this->sequencer();
LOG_F(INFO, "SC53C94: SELECT W/O ATN command started"); LOG_F(INFO, "SC53C94: SELECT W/O ATN command started");
break; break;
case CMD_SELECT_WITH_ATN:
static SeqDesc * sel_with_atn_desc = new SeqDesc[4]{
{SeqState::SEL_BEGIN, 0, INTSTAT_DIS },
{SeqState::SEND_MSG, 2, INTSTAT_SR | INTSTAT_SO},
{SeqState::SEND_CMD, 3, INTSTAT_SR | INTSTAT_SO},
{SeqState::CMD_COMPLETE, 4, INTSTAT_SR | INTSTAT_SO},
};
this->seq_step = 0;
this->bytes_out = 1; // set message length
this->cmd_steps = sel_with_atn_desc;
this->cur_state = SeqState::BUS_FREE;
this->sequencer();
LOG_F(INFO, "SC53C94: SELECT WITH ATN command started");
break;
case CMD_ENA_SEL_RESEL: case CMD_ENA_SEL_RESEL:
exec_next_command(); exec_next_command();
break; break;
@ -424,7 +435,6 @@ void Sc53C94::sequencer()
if (this->bus_obj->end_selection(this->my_bus_id, this->target_id)) { if (this->bus_obj->end_selection(this->my_bus_id, this->target_id)) {
this->bus_obj->release_ctrl_line(this->my_bus_id, SCSI_CTRL_SEL); this->bus_obj->release_ctrl_line(this->my_bus_id, SCSI_CTRL_SEL);
LOG_F(INFO, "SC53C94: selection completed"); LOG_F(INFO, "SC53C94: selection completed");
this->cmd_steps++;
} else { // selection timeout } else { // selection timeout
this->seq_step = this->cmd_steps->step_num; this->seq_step = this->cmd_steps->step_num;
this->int_status |= this->cmd_steps->status; this->int_status |= this->cmd_steps->status;
@ -434,11 +444,19 @@ void Sc53C94::sequencer()
exec_next_command(); exec_next_command();
} }
break; break;
case SeqState::CMD_BEGIN: case SeqState::SEND_MSG:
LOG_F(9, "CMD_BEGIN reached"); this->bus_obj->push_data(this->target_id, this->data_fifo, this->bytes_out);
this->data_fifo_pos -= this->bytes_out;
if (this->data_fifo_pos > 0) {
std::memmove(this->data_fifo, &this->data_fifo[this->bytes_out], this->data_fifo_pos);
}
break;
case SeqState::SEND_CMD:
this->bus_obj->push_data(this->target_id, this->data_fifo, this->data_fifo_pos);
this->data_fifo_pos = 0;
break; break;
case SeqState::CMD_COMPLETE: case SeqState::CMD_COMPLETE:
this->cmd_steps++; this->seq_step = this->cmd_steps->step_num;
this->int_status |= this->cmd_steps->status; this->int_status |= this->cmd_steps->status;
this->update_irq(); this->update_irq();
exec_next_command(); exec_next_command();
@ -449,28 +467,31 @@ void Sc53C94::sequencer()
case ScsiPhase::COMMAND: case ScsiPhase::COMMAND:
case ScsiPhase::DATA_OUT: case ScsiPhase::DATA_OUT:
case ScsiPhase::MESSAGE_OUT: case ScsiPhase::MESSAGE_OUT:
LOG_F(WARNING, "Sc53C94: sending data not unimplemented"); this->bus_obj->push_data(this->target_id, this->data_fifo, this->data_fifo_pos);
this->data_fifo_pos = 0;
this->cur_state = SeqState::XFER_END;
this->cmd_steps++;
this->sequencer();
break; break;
case ScsiPhase::STATUS: case ScsiPhase::STATUS:
case ScsiPhase::DATA_IN: case ScsiPhase::DATA_IN:
case ScsiPhase::MESSAGE_IN: case ScsiPhase::MESSAGE_IN:
this->bus_obj->negotiate_xfer(this->data_fifo_pos, this->bytes_out);
this->cur_state = SeqState::RCV_DATA; this->cur_state = SeqState::RCV_DATA;
this->bus_obj->target_request_data();
this->rcv_data(); this->rcv_data();
if (!(this->cmd_fifo[0] & 0x80)) {
this->cur_state = SeqState::XFER_END;
this->sequencer();
}
} }
break; break;
case SeqState::XFER_END: case SeqState::XFER_END:
if (this->is_initiator) { if (this->is_initiator) {
this->bus_obj->target_next_step(); this->bus_obj->target_next_step();
} }
this->int_status |= this->cmd_steps->status; this->int_status |= INTSTAT_SR;
this->update_irq(); this->update_irq();
if (this->cmd_steps->next_step > 0) { exec_next_command();
this->cur_state = this->cmd_steps->next_step;
this->cmd_steps++;
} else {
exec_next_command();
}
break; break;
case SeqState::RCV_DATA: case SeqState::RCV_DATA:
// check for unexpected bus phase changes // check for unexpected bus phase changes
@ -484,18 +505,18 @@ void Sc53C94::sequencer()
break; break;
case SeqState::RCV_STATUS: case SeqState::RCV_STATUS:
case SeqState::RCV_MESSAGE: case SeqState::RCV_MESSAGE:
this->bus_obj->target_request_data(); this->bus_obj->negotiate_xfer(this->data_fifo_pos, this->bytes_out);
this->rcv_data(); this->rcv_data();
if (this->is_initiator) { if (this->is_initiator) {
if (this->cur_state == SeqState::RCV_STATUS) { if (this->cur_state == SeqState::RCV_STATUS) {
this->bus_obj->target_next_step(); this->bus_obj->target_next_step();
} else if (this->cur_state == SeqState::RCV_MESSAGE) { } else if (this->cur_state == SeqState::RCV_MESSAGE) {
this->bus_obj->assert_ctrl_line(this->my_bus_id, SCSI_CTRL_ACK); this->bus_obj->assert_ctrl_line(this->my_bus_id, SCSI_CTRL_ACK);
this->cmd_steps++;
this->cur_state = this->cmd_steps->next_step;
this->sequencer();
} }
} }
this->cur_state = this->cmd_steps->next_step;
this->cmd_steps++;
this->sequencer();
break; break;
default: default:
ABORT_F("SC53C94: unimplemented sequencer state %d", this->cur_state); ABORT_F("SC53C94: unimplemented sequencer state %d", this->cur_state);
@ -525,34 +546,40 @@ void Sc53C94::notify(ScsiBus* bus_obj, ScsiMsg msg_type, int param)
LOG_F(WARNING, "SC53C94: ignore invalid selection confirmation message"); LOG_F(WARNING, "SC53C94: ignore invalid selection confirmation message");
} }
break; break;
case ScsiMsg::SEND_CMD_BEGIN: case ScsiMsg::BUS_PHASE_CHANGE:
this->cur_state = SeqState::CMD_BEGIN; if (param != ScsiPhase::BUS_FREE && this->cmd_steps != nullptr) {
this->sequencer(); this->cmd_steps++;
break; this->cur_state = this->cmd_steps->next_step;
case ScsiMsg::SEND_CMD_END: this->sequencer();
this->cur_state = SeqState::CMD_COMPLETE; }
this->sequencer();
break; break;
default: default:
LOG_F(9, "SC53C94: ignore notification message, type: %d", msg_type); LOG_F(9, "SC53C94: ignore notification message, type: %d", msg_type);
} }
} }
bool Sc53C94::send_bytes(uint8_t* dst_ptr, int count) int Sc53C94::send_data(uint8_t* dst_ptr, int count)
{ {
if (this->data_fifo_pos < count) { if (dst_ptr == nullptr || !count) {
return false; return 0;
} }
int actual_count = std::min(this->data_fifo_pos, count);
// move data out of the data FIFO // move data out of the data FIFO
std::memcpy(dst_ptr, this->data_fifo, count); std::memcpy(dst_ptr, this->data_fifo, actual_count);
// remove the just readed data from the data FIFO // remove the just readed data from the data FIFO
this->data_fifo_pos -= count; this->data_fifo_pos -= actual_count;
if (this->data_fifo_pos > 0) { if (this->data_fifo_pos > 0) {
std::memmove(this->data_fifo, &this->data_fifo[count], this->data_fifo_pos); std::memmove(this->data_fifo, &this->data_fifo[actual_count], this->data_fifo_pos);
} else {
this->cmd_steps++;
this->cur_state = this->cmd_steps->next_step;
this->sequencer();
} }
return true;
return actual_count;
} }
bool Sc53C94::rcv_data() bool Sc53C94::rcv_data()
@ -564,13 +591,13 @@ bool Sc53C94::rcv_data()
return false; return false;
} }
if (this->cmd_fifo[0] & 0x80) { if ((this->cmd_fifo[0] & 0x80) && this->cur_bus_phase == ScsiPhase::DATA_IN) {
req_count = std::min((int)this->xfer_count, DATA_FIFO_MAX); req_count = std::min((int)this->xfer_count, DATA_FIFO_MAX - this->data_fifo_pos);
} else { } else {
req_count = 1; req_count = 1;
} }
this->bus_obj->target_pull_data(&this->data_fifo[this->data_fifo_pos], req_count); this->bus_obj->pull_data(this->target_id, &this->data_fifo[this->data_fifo_pos], req_count);
this->data_fifo_pos += req_count; this->data_fifo_pos += req_count;
return true; return true;
} }

View File

@ -89,6 +89,7 @@ enum {
CMD_COMPLETE_STEPS = 0x11, CMD_COMPLETE_STEPS = 0x11,
CMD_MSG_ACCEPTED = 0x12, CMD_MSG_ACCEPTED = 0x12,
CMD_SELECT_NO_ATN = 0x41, CMD_SELECT_NO_ATN = 0x41,
CMD_SELECT_WITH_ATN = 0x42,
CMD_ENA_SEL_RESEL = 0x44, CMD_ENA_SEL_RESEL = 0x44,
}; };
@ -123,7 +124,8 @@ namespace SeqState {
ARB_END, ARB_END,
SEL_BEGIN, SEL_BEGIN,
SEL_END, SEL_END,
CMD_BEGIN, SEND_MSG,
SEND_CMD,
CMD_COMPLETE, CMD_COMPLETE,
XFER_BEGIN, XFER_BEGIN,
XFER_END, XFER_END,
@ -162,7 +164,7 @@ public:
void notify(ScsiBus* bus_obj, ScsiMsg msg_type, int param); void notify(ScsiBus* bus_obj, ScsiMsg msg_type, int param);
bool prepare_data() { return false; }; bool prepare_data() { return false; };
bool has_data() { return this->data_fifo_pos != 0; }; bool has_data() { return this->data_fifo_pos != 0; };
bool send_bytes(uint8_t* dst_ptr, int count); int send_data(uint8_t* dst_ptr, int count);
void process_command() {}; void process_command() {};
protected: protected:
@ -190,6 +192,7 @@ private:
uint8_t data_fifo[16]; uint8_t data_fifo[16];
int cmd_fifo_pos; int cmd_fifo_pos;
int data_fifo_pos; int data_fifo_pos;
int bytes_out;
bool on_reset = false; bool on_reset = false;
uint32_t xfer_count; uint32_t xfer_count;
uint32_t set_xfer_count; uint32_t set_xfer_count;