sc53c94: support interrupts.

This commit is contained in:
Maxim Poliakovski 2022-02-06 01:50:19 +01:00
parent 298135fd7a
commit 00093bdc95
4 changed files with 58 additions and 4 deletions

View File

@ -23,6 +23,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <core/timermanager.h>
#include <devices/common/hwcomponent.h>
#include <devices/common/hwinterrupt.h>
#include <devices/common/scsi/sc53c94.h>
#include <loguru.hpp>
#include <machines/machinebase.h>
@ -41,6 +42,11 @@ int Sc53C94::device_postinit()
{
this->bus_obj = dynamic_cast<ScsiBus*>(gMachineObj->get_comp_by_name("SCSI0"));
this->bus_obj->register_device(7, static_cast<ScsiDevice*>(this));
this->int_ctrl = dynamic_cast<InterruptCtrl*>(
gMachineObj->get_comp_by_type(HWCompType::INT_CTRL));
this->irq_id = this->int_ctrl->register_dev_int(IntSrc::SCSI1);
return 0;
}
@ -61,17 +67,31 @@ void Sc53C94::reset_device()
this->data_fifo[0] = 0;
this->seq_step = 0;
this->status = 0;
}
uint8_t Sc53C94::read(uint8_t reg_offset)
{
uint8_t int_status;
switch (reg_offset) {
case Read::Reg53C94::Command:
return this->cmd_fifo[0];
case Read::Reg53C94::Status:
return this->status;
case Read::Reg53C94::Int_Status:
return this->int_status;
int_status = this->int_status;
this->seq_step = 0;
this->int_status = 0;
this->update_irq();
return int_status;
case Read::Reg53C94::Seq_Step:
return this->seq_step;
case Read::Reg53C94::FIFO_Flags:
return (this->seq_step << 5) | (this->data_fifo_pos & 0x1F);
case Read::Reg53C94::Config_3:
return this->config3;
case Read::Reg53C94::Xfer_Cnt_Hi:
if (this->config2 & CFG2_ENF) {
return (this->xfer_count >> 16) & 0xFFU;
@ -197,7 +217,7 @@ void Sc53C94::exec_command()
break;
case CMD_SELECT_NO_ATN:
static SeqDesc sel_no_atn_desc[] {
{SeqState::SEL_BEGIN, 2, INTSTAT_SR | INTSTAT_SO},
{SeqState::SEL_BEGIN, 0, INTSTAT_DIS },
{SeqState::CMD_BEGIN, 3, INTSTAT_SR | INTSTAT_SO},
{SeqState::CMD_COMPLETE, 4, INTSTAT_SR | INTSTAT_SO},
};
@ -207,6 +227,10 @@ void Sc53C94::exec_command()
sequencer();
LOG_F(INFO, "SC53C94: SELECT W/O ATN command started");
break;
case CMD_ENA_SEL_RESEL:
LOG_F(INFO, "SC53C94: ENABLE SELECTION/RESELECTION command executed");
exec_next_command();
break;
default:
LOG_F(ERROR, "SC53C94: invalid/unimplemented command 0x%X", cmd);
this->cmd_fifo_pos--; // remove invalid command from FIFO
@ -296,8 +320,9 @@ void Sc53C94::sequencer()
} else { // selection timeout
this->seq_step = this->cmd_steps->step_num;
this->int_status |= this->cmd_steps->status;
this->bus_obj->release_ctrl_lines(this->my_bus_id);
this->bus_obj->disconnect(this->my_bus_id);
this->cur_state = SeqState::IDLE;
this->update_irq();
exec_next_command();
}
break;
@ -306,6 +331,16 @@ void Sc53C94::sequencer()
}
}
void Sc53C94::update_irq()
{
uint8_t new_irq = !!(this->int_status != 0);
if (new_irq != this->irq) {
this->irq = new_irq;
this->status = (this->status & 0x7F) | (new_irq << 7);
this->int_ctrl->ack_int(this->irq_id, new_irq);
}
}
void Sc53C94::notify(ScsiMsg msg_type, int param)
{
switch (msg_type) {

View File

@ -30,6 +30,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#define SC_53C94_H
#include "scsi.h"
#include "devices/common/hwinterrupt.h"
#include <cinttypes>
@ -82,6 +83,7 @@ enum {
CMD_RESET_BUS = 3,
CMD_DMA_STOP = 4,
CMD_SELECT_NO_ATN = 0x41,
CMD_ENA_SEL_RESEL = 0x44,
};
/** Interrupt status register bits. */
@ -146,6 +148,8 @@ protected:
void sequencer();
void seq_defer_state(uint64_t delay_ns);
void update_irq();
private:
uint8_t chip_id;
uint8_t my_bus_id;
@ -177,6 +181,11 @@ private:
SeqDesc* cmd_steps;
bool is_initiator;
uint8_t cur_cmd;
// interrupt related stuff
InterruptCtrl* int_ctrl = nullptr;
uint32_t irq_id = 0;
uint8_t irq = 0;
};
#endif // SC_53C94_H

View File

@ -90,7 +90,7 @@ public:
void assert_ctrl_line(int id, uint16_t mask);
void release_ctrl_line(int id, uint16_t mask);
void release_ctrl_lines(int id);
int current_phase() { return this->cur_phase; };
int current_phase() { return this->cur_phase; };
// high-level control/status
bool begin_arbitration(int id);
@ -98,6 +98,7 @@ public:
bool begin_selection(int initiator_id, int target_id, bool atn);
void confirm_selection(int target_id);
bool end_selection(int initiator_id, int target_id);
void disconnect(int dev_id);
protected:
void change_bus_phase(int initiator_id);

View File

@ -170,3 +170,12 @@ bool ScsiBus::end_selection(int initiator_id, int target_id)
// check for selection confirmation from target
return this->target_id == target_id;
}
void ScsiBus::disconnect(int dev_id)
{
this->release_ctrl_lines(dev_id);
if (!(this->ctrl_lines & SCSI_CTRL_BSY) && !(this->ctrl_lines & SCSI_CTRL_SEL)) {
this->cur_phase = ScsiPhase::BUS_FREE;
change_bus_phase(dev_id);
}
}