mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-25 03:29:38 +00:00
sc53c94: refactor state machine.
This commit is contained in:
parent
40a02cc0f7
commit
ca5f81417f
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user