mirror of
https://github.com/akuker/RASCSI.git
synced 2024-06-10 02:29:33 +00:00
1122 lines
37 KiB
C++
1122 lines
37 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// SCSI Target Emulator RaSCSI Reloaded
|
|
// for Raspberry Pi
|
|
//
|
|
// Powered by XM6 TypeG Technology.
|
|
// Copyright (C) 2016-2020 GIMONS
|
|
//
|
|
// [ GPIO-SCSI bus ]
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "hal/gpiobus.h"
|
|
#include "config.h"
|
|
#include "hal/sbc_version.h"
|
|
#include "hal/systimer.h"
|
|
#include "log.h"
|
|
#include "os.h"
|
|
#include <array>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/time.h>
|
|
#ifdef __linux__
|
|
#include <sys/epoll.h>
|
|
#endif
|
|
|
|
// #if defined CONNECT_TYPE_STANDARD
|
|
// #include "hal/gpiobus_standard.h"
|
|
// #elif defined CONNECT_TYPE_FULLSPEC
|
|
// #include "hal/gpiobus_fullspec.h"
|
|
// #elif defined CONNECT_TYPE_AIBOM
|
|
// #include "hal/gpiobus_aibom.h"
|
|
// #elif defined CONNECT_TYPE_GAMERNIUM
|
|
// #include "hal/gpiobus_gamernium.h"
|
|
// #else
|
|
// #error Invalid connection type or none specified
|
|
// #endif
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Constant declarations (bus control timing)
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
// SCSI Bus timings taken from:
|
|
// https://www.staff.uni-mainz.de/tacke/scsi/SCSI2-05.html
|
|
[[maybe_unused]] const static int SCSI_DELAY_ARBITRATION_DELAY_NS = 2400;
|
|
[[maybe_unused]] const static int SCSI_DELAY_ASSERTION_PERIOD_NS = 90;
|
|
[[maybe_unused]] const static int SCSI_DELAY_BUS_CLEAR_DELAY_NS = 800;
|
|
[[maybe_unused]] const static int SCSI_DELAY_BUS_FREE_DELAY_NS = 800;
|
|
[[maybe_unused]] const static int SCSI_DELAY_BUS_SET_DELAY_NS = 1800;
|
|
[[maybe_unused]] const static int SCSI_DELAY_BUS_SETTLE_DELAY_NS = 400;
|
|
[[maybe_unused]] const static int SCSI_DELAY_CABLE_SKEW_DELAY_NS = 10;
|
|
[[maybe_unused]] const static int SCSI_DELAY_DATA_RELEASE_DELAY_NS = 400;
|
|
[[maybe_unused]] const static int SCSI_DELAY_DESKEW_DELAY_NS = 45;
|
|
[[maybe_unused]] const static int SCSI_DELAY_DISCONNECTION_DELAY_US = 200;
|
|
[[maybe_unused]] const static int SCSI_DELAY_HOLD_TIME_NS = 45;
|
|
[[maybe_unused]] const static int SCSI_DELAY_NEGATION_PERIOD_NS = 90;
|
|
[[maybe_unused]] const static int SCSI_DELAY_POWER_ON_TO_SELECTION_TIME_S = 10; // (recommended)
|
|
[[maybe_unused]] const static int SCSI_DELAY_RESET_TO_SELECTION_TIME_US = 250 * 1000; // (recommended)
|
|
[[maybe_unused]] const static int SCSI_DELAY_RESET_HOLD_TIME_US = 25;
|
|
[[maybe_unused]] const static int SCSI_DELAY_SELECTION_ABORT_TIME_US = 200;
|
|
[[maybe_unused]] const static int SCSI_DELAY_SELECTION_TIMEOUT_DELAY_NS = 250 * 1000; // (recommended)
|
|
[[maybe_unused]] const static int SCSI_DELAY_FAST_ASSERTION_PERIOD_NS = 30;
|
|
[[maybe_unused]] const static int SCSI_DELAY_FAST_CABLE_SKEW_DELAY_NS = 5;
|
|
[[maybe_unused]] const static int SCSI_DELAY_FAST_DESKEW_DELAY_NS = 20;
|
|
[[maybe_unused]] const static int SCSI_DELAY_FAST_HOLD_TIME_NS = 10;
|
|
[[maybe_unused]] const static int SCSI_DELAY_FAST_NEGATION_PERIOD_NS = 30;
|
|
|
|
// The DaynaPort SCSI Link do a short delay in the middle of transfering
|
|
// a packet. This is the number of uS that will be delayed between the
|
|
// header and the actual data.
|
|
const static int SCSI_DELAY_SEND_DATA_DAYNAPORT_US = 100;
|
|
|
|
using namespace std;
|
|
|
|
// Nothing SBC hardware specific should be done in this function
|
|
bool GPIOBUS::Init(mode_e mode, board_type::rascsi_board_type_e rascsi_type)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
|
|
// Figure out what type of board is connected.
|
|
switch (rascsi_type) {
|
|
case board_type::rascsi_board_type_e::BOARD_TYPE_AIBOM:
|
|
board = make_shared<board_type::Rascsi_Board_Type>(board_type::board_definition_aibom);
|
|
break;
|
|
case board_type::rascsi_board_type_e::BOARD_TYPE_FULLSPEC:
|
|
board = make_shared<board_type::Rascsi_Board_Type>(board_type::board_definition_fullspec);
|
|
break;
|
|
case board_type::rascsi_board_type_e::BOARD_TYPE_GAMERNIUM:
|
|
board = make_shared<board_type::Rascsi_Board_Type>(board_type::board_definition_gamernium);
|
|
break;
|
|
case board_type::rascsi_board_type_e::BOARD_TYPE_STANDARD:
|
|
board = make_shared<board_type::Rascsi_Board_Type>(board_type::board_definition_standard);
|
|
break;
|
|
}
|
|
LOGINFO("Detected board type: %s", board->connect_desc.c_str());
|
|
|
|
// Save operation mode
|
|
actmode = mode;
|
|
|
|
SignalTable.push_back(board->pin_dt0);
|
|
SignalTable.push_back(board->pin_dt1);
|
|
SignalTable.push_back(board->pin_dt2);
|
|
SignalTable.push_back(board->pin_dt3);
|
|
SignalTable.push_back(board->pin_dt4);
|
|
SignalTable.push_back(board->pin_dt5);
|
|
SignalTable.push_back(board->pin_dt6);
|
|
SignalTable.push_back(board->pin_dt7);
|
|
SignalTable.push_back(board->pin_dp);
|
|
SignalTable.push_back(board->pin_sel);
|
|
SignalTable.push_back(board->pin_atn);
|
|
SignalTable.push_back(board->pin_rst);
|
|
SignalTable.push_back(board->pin_ack);
|
|
SignalTable.push_back(board->pin_bsy);
|
|
SignalTable.push_back(board->pin_msg);
|
|
SignalTable.push_back(board->pin_cd);
|
|
SignalTable.push_back(board->pin_io);
|
|
SignalTable.push_back(board->pin_req);
|
|
|
|
return true;
|
|
}
|
|
|
|
// The GPIO hardware needs to be initialized before calling this function.
|
|
void GPIOBUS::InitializeGpio()
|
|
{
|
|
// Set pull up/pull down
|
|
LOGTRACE("%s Set pull up/down....", __PRETTY_FUNCTION__);
|
|
board_type::gpio_pull_up_down_e pullmode;
|
|
if (board->signal_control_mode == 0) {
|
|
// #if SIGNAL_CONTROL_MODE == 0
|
|
LOGTRACE("%s GPIO_PULLNONE", __PRETTY_FUNCTION__);
|
|
pullmode = board_type::gpio_pull_up_down_e::GPIO_PULLNONE;
|
|
} else if (board->signal_control_mode == 1) {
|
|
// #elif SIGNAL_CONTROL_MODE == 1
|
|
LOGTRACE("%s GPIO_PULLUP", __PRETTY_FUNCTION__);
|
|
pullmode = board_type::gpio_pull_up_down_e ::GPIO_PULLUP;
|
|
} else {
|
|
// #else
|
|
LOGTRACE("%s GPIO_PULLDOWN", __PRETTY_FUNCTION__);
|
|
pullmode = board_type::gpio_pull_up_down_e ::GPIO_PULLDOWN;
|
|
}
|
|
// #endif
|
|
|
|
// Initialize all signals
|
|
LOGTRACE("%s Initialize all signals....", __PRETTY_FUNCTION__);
|
|
|
|
for (auto cur_signal : SignalTable){
|
|
PinSetSignal(cur_signal, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
PinConfig(cur_signal, board_type::gpio_direction_e::GPIO_INPUT);
|
|
PullConfig(cur_signal, pullmode);
|
|
}
|
|
|
|
// Set control signals
|
|
LOGTRACE("%s Set control signals....", __PRETTY_FUNCTION__);
|
|
PinSetSignal(board->pin_act, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
PinSetSignal(board->pin_tad, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
PinSetSignal(board->pin_ind, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
PinSetSignal(board->pin_dtd, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
PinConfig(board->pin_act, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
PinConfig(board->pin_tad, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
PinConfig(board->pin_ind, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
PinConfig(board->pin_dtd, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
|
|
// Set the ENABLE signal
|
|
// This is used to show that the application is running
|
|
PinSetSignal(board->pin_enb, board->EnbOff());
|
|
PinConfig(board->pin_enb, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
}
|
|
|
|
void GPIOBUS::Cleanup()
|
|
{
|
|
#if defined(__x86_64__) || defined(__X86__)
|
|
return;
|
|
#else
|
|
// Release SEL signal interrupt
|
|
#ifdef USE_SEL_EVENT_ENABLE
|
|
close(selevreq.fd);
|
|
#endif // USE_SEL_EVENT_ENABLE
|
|
|
|
// Set control signals
|
|
PinSetSignal(board->pin_enb, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
PinSetSignal(board->pin_act, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
PinSetSignal(board->pin_tad, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
PinSetSignal(board->pin_ind, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
PinSetSignal(board->pin_dtd, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
PinConfig(board->pin_act, board_type::gpio_direction_e::GPIO_INPUT);
|
|
PinConfig(board->pin_tad, board_type::gpio_direction_e::GPIO_INPUT);
|
|
PinConfig(board->pin_ind, board_type::gpio_direction_e::GPIO_INPUT);
|
|
PinConfig(board->pin_dtd, board_type::gpio_direction_e::GPIO_INPUT);
|
|
|
|
// Initialize all signals
|
|
for (board_type::pi_physical_pin_e pin : SignalTable) {
|
|
if (pin != board_type::pi_physical_pin_e::PI_PHYS_PIN_NONE) {
|
|
PinSetSignal(pin, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
PinConfig(pin, board_type::gpio_direction_e::GPIO_INPUT);
|
|
PullConfig(pin, board_type::gpio_pull_up_down_e::GPIO_PULLNONE);
|
|
}
|
|
}
|
|
|
|
// Set drive strength back to 8mA
|
|
DrvConfig(3);
|
|
#endif // ifdef __x86_64__ || __X86__
|
|
}
|
|
|
|
void GPIOBUS::Reset()
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
#if defined(__x86_64__) || defined(__X86__)
|
|
return;
|
|
#else
|
|
|
|
// Turn off active signal
|
|
SetControl(board->pin_act, board->ActOff());
|
|
|
|
for (board_type::pi_physical_pin_e pin : SignalTable) {
|
|
if (pin != board_type::pi_physical_pin_e::PI_PHYS_PIN_NONE) {
|
|
SetSignal(pin, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
}
|
|
}
|
|
|
|
if (actmode == mode_e::TARGET) {
|
|
// Target mode
|
|
|
|
// Set target signal to input
|
|
SetControl(board->pin_tad, board->TadIn());
|
|
SetMode(board->pin_bsy, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_msg, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_cd, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_req, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_io, board_type::gpio_direction_e::GPIO_INPUT);
|
|
|
|
// Set the initiator signal to input
|
|
SetControl(board->pin_ind, board->IndIn());
|
|
SetMode(board->pin_sel, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_atn, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_ack, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_rst, board_type::gpio_direction_e::GPIO_INPUT);
|
|
|
|
// Set data bus signals to input
|
|
SetControl(board->pin_dtd, board->DtdIn());
|
|
SetMode(board->pin_dt0, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt1, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt2, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt3, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt4, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt5, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt6, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt7, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dp, board_type::gpio_direction_e::GPIO_INPUT);
|
|
} else {
|
|
// Initiator mode
|
|
|
|
// Set target signal to input
|
|
SetControl(board->pin_tad, board->TadIn());
|
|
SetMode(board->pin_bsy, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_msg, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_cd, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_req, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_io, board_type::gpio_direction_e::GPIO_INPUT);
|
|
|
|
// Set the initiator signal to output
|
|
SetControl(board->pin_ind, board->IndOut());
|
|
SetMode(board->pin_sel, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_atn, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_ack, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_rst, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
|
|
// Set the data bus signals to output
|
|
SetControl(board->pin_dtd, board->DtdOut());
|
|
SetMode(board->pin_dt0, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt1, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt2, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt3, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt4, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt5, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt6, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt7, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dp, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
}
|
|
|
|
// Re-read all signals
|
|
Acquire();
|
|
// signals = 0;
|
|
#endif // ifdef __x86_64__ || __X86__
|
|
}
|
|
|
|
void GPIOBUS::SetENB(bool ast)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
PinSetSignal(board->pin_enb, ast ? board->EnbOn() : board->EnbOff());
|
|
}
|
|
|
|
bool GPIOBUS::GetBSY() const
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
return GetSignal(board->pin_bsy);
|
|
}
|
|
|
|
void GPIOBUS::SetBSY(bool ast)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
// Set BSY signal
|
|
SetSignal(board->pin_bsy, board->bool_to_gpio_state(ast));
|
|
|
|
if (actmode == mode_e::TARGET) {
|
|
if (ast) {
|
|
// Turn on ACTIVE signal
|
|
SetControl(board->pin_act, board->act_on);
|
|
|
|
// Set Target signal to output
|
|
SetControl(board->pin_tad, board->TadOut());
|
|
|
|
SetMode(board->pin_bsy, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_msg, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_cd, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_req, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_io, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
} else {
|
|
// Turn off the ACTIVE signal
|
|
SetControl(board->pin_act, board->ActOff());
|
|
|
|
// Set the target signal to input
|
|
SetControl(board->pin_tad, board->TadIn());
|
|
|
|
SetMode(board->pin_bsy, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_msg, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_cd, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_req, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_io, board_type::gpio_direction_e::GPIO_INPUT);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool GPIOBUS::GetSEL() const
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
return GetSignal(board->pin_sel);
|
|
}
|
|
|
|
void GPIOBUS::SetSEL(bool ast)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
if (actmode == mode_e::INITIATOR && ast) {
|
|
// Turn on ACTIVE signal
|
|
SetControl(board->pin_act, board->act_on);
|
|
}
|
|
|
|
// Set SEL signal
|
|
SetSignal(board->pin_sel, board->bool_to_gpio_state(ast));
|
|
}
|
|
|
|
bool GPIOBUS::GetATN() const
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
return GetSignal(board->pin_atn);
|
|
}
|
|
|
|
void GPIOBUS::SetATN(bool ast)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
SetSignal(board->pin_atn, board->bool_to_gpio_state(ast));
|
|
}
|
|
|
|
bool GPIOBUS::GetACK() const
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
return GetSignal(board->pin_ack);
|
|
}
|
|
|
|
void GPIOBUS::SetACK(bool ast)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
SetSignal(board->pin_ack, board->bool_to_gpio_state(ast));
|
|
}
|
|
|
|
bool GPIOBUS::GetACT() const
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
return GetSignal(board->pin_act);
|
|
}
|
|
|
|
void GPIOBUS::SetACT(bool ast)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
SetSignal(board->pin_act, (ast) ? board->ActOn() : board->ActOff());
|
|
}
|
|
|
|
bool GPIOBUS::GetRST() const
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
return GetSignal(board->pin_rst);
|
|
}
|
|
|
|
void GPIOBUS::SetRST(bool ast)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
SetSignal(board->pin_rst, (ast) ? board->act_on : board->ActOff());
|
|
}
|
|
|
|
bool GPIOBUS::GetMSG() const
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
return GetSignal(board->pin_msg);
|
|
}
|
|
|
|
void GPIOBUS::SetMSG(bool ast)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
SetSignal(board->pin_msg, board->bool_to_gpio_state(ast));
|
|
}
|
|
|
|
bool GPIOBUS::GetCD() const
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
return GetSignal(board->pin_cd);
|
|
}
|
|
|
|
void GPIOBUS::SetCD(bool ast)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
SetSignal(board->pin_cd, board->bool_to_gpio_state(ast));
|
|
}
|
|
|
|
bool GPIOBUS::GetIO()
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
bool ast = GetSignal(board->pin_io);
|
|
|
|
if (actmode == mode_e::INITIATOR) {
|
|
// Change the data input/output direction by IO signal
|
|
if (ast) {
|
|
SetControl(board->pin_dtd, board->DtdIn());
|
|
SetMode(board->pin_dt0, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt1, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt2, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt3, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt4, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt5, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt6, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt7, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dp, board_type::gpio_direction_e::GPIO_INPUT);
|
|
} else {
|
|
SetControl(board->pin_dtd, board->DtdOut());
|
|
SetMode(board->pin_dt0, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt1, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt2, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt3, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt4, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt5, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt6, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt7, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dp, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
}
|
|
}
|
|
|
|
return ast;
|
|
}
|
|
|
|
void GPIOBUS::SetIO(bool ast)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
SetSignal(board->pin_io, board->bool_to_gpio_state(ast));
|
|
|
|
if (actmode == mode_e::TARGET) {
|
|
// Change the data input/output direction by IO signal
|
|
if (ast) {
|
|
SetControl(board->pin_dtd, board->DtdOut());
|
|
SetDAT(0);
|
|
SetMode(board->pin_dt0, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt1, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt2, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt3, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt4, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt5, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt6, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dt7, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
SetMode(board->pin_dp, board_type::gpio_direction_e::GPIO_OUTPUT);
|
|
} else {
|
|
SetControl(board->pin_dtd, board->DtdIn());
|
|
SetMode(board->pin_dt0, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt1, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt2, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt3, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt4, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt5, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt6, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dt7, board_type::gpio_direction_e::GPIO_INPUT);
|
|
SetMode(board->pin_dp, board_type::gpio_direction_e::GPIO_INPUT);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool GPIOBUS::GetREQ() const
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
return GetSignal(board->pin_req);
|
|
}
|
|
|
|
void GPIOBUS::SetREQ(bool ast)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
SetSignal(board->pin_req, board->bool_to_gpio_state(ast));
|
|
}
|
|
|
|
bool GPIOBUS::GetDP() const
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
return GetSignal(board->pin_dp);
|
|
}
|
|
|
|
// Extract as specific pin field from a raw data capture
|
|
uint32_t GPIOBUS::GetPinRaw(uint32_t raw_data, board_type::pi_physical_pin_e pin_num)
|
|
{
|
|
// return GetSignalRaw(raw_data, pin_num);
|
|
(void)raw_data;
|
|
(void)pin_num;
|
|
LOGWARN("THIS FUNCTION ISN'T IMPLEMENTED YET");
|
|
return 0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Receive command handshake
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
int GPIOBUS::CommandHandShake(BYTE *buf)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
// Only works in TARGET mode
|
|
if (actmode != mode_e::TARGET) {
|
|
return 0;
|
|
}
|
|
|
|
DisableIRQ();
|
|
|
|
// Assert REQ signal
|
|
SetSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
// Wait for ACK signal
|
|
bool ret = WaitSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
// Wait until the signal line stabilizes
|
|
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
|
|
|
|
// Get data
|
|
*buf = GetDAT();
|
|
|
|
// Disable REQ signal
|
|
SetSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
// Timeout waiting for ACK assertion
|
|
if (!ret) {
|
|
EnableIRQ();
|
|
return 0;
|
|
}
|
|
|
|
// Wait for ACK to clear
|
|
ret = WaitSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
// Timeout waiting for ACK to clear
|
|
if (!ret) {
|
|
EnableIRQ();
|
|
return 0;
|
|
}
|
|
|
|
// The ICD AdSCSI ST, AdSCSI Plus ST and AdSCSI Micro ST host adapters allow SCSI devices to be connected
|
|
// to the ACSI bus of Atari ST/TT computers and some clones. ICD-aware drivers prepend a $1F byte in front
|
|
// of the CDB (effectively resulting in a custom SCSI command) in order to get access to the full SCSI
|
|
// command set. Native ACSI is limited to the low SCSI command classes with command bytes < $20.
|
|
// Most other host adapters (e.g. LINK96/97 and the one by Inventronik) and also several devices (e.g.
|
|
// UltraSatan or GigaFile) that can directly be connected to the Atari's ACSI port also support ICD
|
|
// semantics. I fact, these semantics have become a standard in the Atari world.
|
|
|
|
// RaSCSI becomes ICD compatible by ignoring the prepended $1F byte before processing the CDB.
|
|
if (*buf == 0x1F) {
|
|
SetSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
ret = WaitSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
|
|
|
|
// Get the actual SCSI command
|
|
*buf = GetDAT();
|
|
|
|
SetSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
if (!ret) {
|
|
EnableIRQ();
|
|
return 0;
|
|
}
|
|
|
|
WaitSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
if (!ret) {
|
|
EnableIRQ();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int command_byte_count = GetCommandByteCount(*buf);
|
|
|
|
// Increment buffer pointer
|
|
buf++;
|
|
|
|
int bytes_received;
|
|
for (bytes_received = 1; bytes_received < command_byte_count; bytes_received++) {
|
|
// Assert REQ signal
|
|
SetSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
// Wait for ACK signal
|
|
ret = WaitSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
// Wait until the signal line stabilizes
|
|
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
|
|
|
|
// Get data
|
|
*buf = GetDAT();
|
|
|
|
// Clear the REQ signal
|
|
SetSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
// Check for timeout waiting for ACK assertion
|
|
if (!ret) {
|
|
break;
|
|
}
|
|
|
|
// Wait for ACK to clear
|
|
ret = WaitSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
// Check for timeout waiting for ACK to clear
|
|
if (!ret) {
|
|
break;
|
|
}
|
|
|
|
// Advance the buffer pointer to receive the next byte
|
|
buf++;
|
|
}
|
|
|
|
EnableIRQ();
|
|
|
|
return bytes_received;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Data reception handshake
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
int GPIOBUS::ReceiveHandShake(BYTE *buf, int count)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
|
|
int i;
|
|
|
|
// Disable IRQs
|
|
DisableIRQ();
|
|
|
|
if (actmode == mode_e::TARGET) {
|
|
for (i = 0; i < count; i++) {
|
|
// Assert the REQ signal
|
|
SetSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
// Wait for ACK
|
|
bool ret = WaitSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
// Wait until the signal line stabilizes
|
|
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
|
|
|
|
// Get data
|
|
*buf = GetDAT();
|
|
|
|
// Clear the REQ signal
|
|
SetSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
// Check for timeout waiting for ACK signal
|
|
if (!ret) {
|
|
break;
|
|
}
|
|
|
|
// Wait for ACK to clear
|
|
ret = WaitSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
// Check for timeout waiting for ACK to clear
|
|
if (!ret) {
|
|
break;
|
|
}
|
|
|
|
// Advance the buffer pointer to receive the next byte
|
|
buf++;
|
|
}
|
|
} else {
|
|
// Get phase
|
|
// uint32_t phase = Acquire() & GPIO_MCI;
|
|
(void)Acquire();
|
|
phase_t phase = GetPhase();
|
|
|
|
for (i = 0; i < count; i++) {
|
|
// Wait for the REQ signal to be asserted
|
|
bool ret = WaitSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
// Check for timeout waiting for REQ signal
|
|
if (!ret) {
|
|
break;
|
|
}
|
|
|
|
// Phase error
|
|
(void)Acquire();
|
|
if (GetPhase() != phase) {
|
|
break;
|
|
}
|
|
|
|
// Wait until the signal line stabilizes
|
|
SysTimer::SleepNsec(SCSI_DELAY_BUS_SETTLE_DELAY_NS);
|
|
|
|
// Get data
|
|
*buf = GetDAT();
|
|
|
|
// Assert the ACK signal
|
|
SetSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
// Wait for REQ to clear
|
|
ret = WaitSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
// Clear the ACK signal
|
|
SetSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
// Check for timeout waiting for REQ to clear
|
|
if (!ret) {
|
|
break;
|
|
}
|
|
|
|
// Phase error
|
|
(void)Acquire();
|
|
if (GetPhase() != phase) {
|
|
break;
|
|
}
|
|
|
|
// Advance the buffer pointer to receive the next byte
|
|
buf++;
|
|
}
|
|
}
|
|
|
|
// Re-enable IRQ
|
|
EnableIRQ();
|
|
|
|
// Return the number of bytes received
|
|
return i;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Data transmission handshake
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
int GPIOBUS::SendHandShake(BYTE *buf, int count, int delay_after_bytes)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
|
|
int i;
|
|
|
|
// Disable IRQs
|
|
DisableIRQ();
|
|
|
|
if (actmode == mode_e::TARGET) {
|
|
for (i = 0; i < count; i++) {
|
|
if (i == delay_after_bytes) {
|
|
LOGTRACE("%s DELAYING for %dus after %d bytes", __PRETTY_FUNCTION__, SCSI_DELAY_SEND_DATA_DAYNAPORT_US,
|
|
(int)delay_after_bytes)
|
|
SysTimer::SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US);
|
|
}
|
|
|
|
// Set the DATA signals
|
|
SetDAT(*buf);
|
|
|
|
// Wait for ACK to clear
|
|
bool ret = WaitSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
// Check for timeout waiting for ACK to clear
|
|
if (!ret) {
|
|
break;
|
|
}
|
|
|
|
// Already waiting for ACK to clear
|
|
|
|
// Assert the REQ signal
|
|
SetSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
// Wait for ACK
|
|
ret = WaitSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
// Clear REQ signal
|
|
SetSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
// Check for timeout waiting for ACK to clear
|
|
if (!ret) {
|
|
break;
|
|
}
|
|
|
|
// Advance the data buffer pointer to receive the next byte
|
|
buf++;
|
|
}
|
|
|
|
// Wait for ACK to clear
|
|
WaitSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
} else {
|
|
// Get Phase
|
|
// uint32_t phase = Acquire() & GPIO_MCI;
|
|
(void)Acquire();
|
|
phase_t phase = GetPhase();
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (i == delay_after_bytes) {
|
|
LOGTRACE("%s DELAYING for %dus after %d bytes", __PRETTY_FUNCTION__, SCSI_DELAY_SEND_DATA_DAYNAPORT_US,
|
|
(int)delay_after_bytes)
|
|
SysTimer::SleepUsec(SCSI_DELAY_SEND_DATA_DAYNAPORT_US);
|
|
}
|
|
|
|
// Set the DATA signals
|
|
SetDAT(*buf);
|
|
|
|
// Wait for REQ to be asserted
|
|
bool ret = WaitSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
// Check for timeout waiting for REQ to be asserted
|
|
if (!ret) {
|
|
break;
|
|
}
|
|
|
|
// Phase error
|
|
Acquire();
|
|
if (GetPhase() != phase) {
|
|
break;
|
|
}
|
|
|
|
// Already waiting for REQ assertion
|
|
|
|
// Assert the ACK signal
|
|
SetSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_HIGH);
|
|
|
|
// Wait for REQ to clear
|
|
ret = WaitSignal(board->pin_req, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
// Clear the ACK signal
|
|
SetSignal(board->pin_ack, board_type::gpio_high_low_e::GPIO_STATE_LOW);
|
|
|
|
// Check for timeout waiting for REQ to clear
|
|
if (!ret) {
|
|
break;
|
|
}
|
|
|
|
// Phase error
|
|
Acquire();
|
|
if (GetPhase() != phase) {
|
|
break;
|
|
}
|
|
|
|
// Advance the data buffer pointer to receive the next byte
|
|
buf++;
|
|
}
|
|
}
|
|
|
|
// Re-enable IRQ
|
|
EnableIRQ();
|
|
|
|
// Return number of transmissions
|
|
return i;
|
|
}
|
|
|
|
#ifdef USE_SEL_EVENT_ENABLE
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// SEL signal event polling
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
bool GPIOBUS::PollSelectEvent()
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
errno = 0;
|
|
|
|
if (epoll_event epev; epoll_wait(epfd, &epev, 1, -1) <= 0) {
|
|
LOGWARN("%s epoll_wait failed", __PRETTY_FUNCTION__)
|
|
LOGWARN("[%08X] %s", errno, strerror(errno))
|
|
return false;
|
|
}
|
|
|
|
if (gpioevent_data gpev; read(selevreq.fd, &gpev, sizeof(gpev)) < 0) {
|
|
LOGWARN("%s read failed", __PRETTY_FUNCTION__)
|
|
LOGWARN("[%08X] %s", errno, strerror(errno))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Cancel SEL signal event
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void GPIOBUS::ClearSelectEvent()
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
}
|
|
#endif // USE_SEL_EVENT_ENABLE
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Signal table
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
vector<board_type::pi_physical_pin_e> GPIOBUS::SignalTable;
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Create work table
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void GPIOBUS::MakeTable(void)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
|
|
[[maybe_unused]] const array<board_type::pi_physical_pin_e, 9> pintbl = {
|
|
board->pin_dt0, board->pin_dt1, board->pin_dt2, board->pin_dt3, board->pin_dt4,
|
|
board->pin_dt5, board->pin_dt6, board->pin_dt7, board->pin_dp};
|
|
|
|
array<bool, 256> tblParity;
|
|
|
|
// Create parity table
|
|
for (uint32_t i = 0; i < 0x100; i++) {
|
|
uint32_t bits = i;
|
|
uint32_t parity = 0;
|
|
for (int j = 0; j < 8; j++) {
|
|
parity ^= bits & 1;
|
|
bits >>= 1;
|
|
}
|
|
parity = ~parity;
|
|
tblParity[i] = parity & 1;
|
|
}
|
|
|
|
#if SIGNAL_CONTROL_MODE == 0
|
|
// Mask and setting data generation
|
|
for (auto &tbl : tblDatMsk) {
|
|
tbl.fill(-1);
|
|
}
|
|
for (auto &tbl : tblDatSet) {
|
|
tbl.fill(0);
|
|
}
|
|
|
|
for (uint32_t i = 0; i < 0x100; i++) {
|
|
// Bit string for inspection
|
|
uint32_t bits = i;
|
|
// TODO: temporary to make clang++ happy.....
|
|
(void)bits;
|
|
|
|
// Get parity
|
|
if (tblParity[i]) {
|
|
bits |= (1 << 8);
|
|
}
|
|
|
|
// TODO: THIS NEEDS TO BE MOVED DOWN TO THE BOARD_SPECIFIC REGION
|
|
// // Bit check
|
|
// for (int j = 0; j < 9; j++) {
|
|
// // Index and shift amount calculation
|
|
// int index = pintbl[j] / 10;
|
|
// int shift = (pintbl[j] % 10) * 3;
|
|
|
|
// // Mask data
|
|
// tblDatMsk[index][i] &= ~(0x7 << shift);
|
|
|
|
// // Setting data
|
|
// if (bits & 1) {
|
|
// tblDatSet[index][i] |= (1 << shift);
|
|
// }
|
|
|
|
// bits >>= 1;
|
|
// }
|
|
}
|
|
#else
|
|
for (uint32_t i = 0; i < 0x100; i++) {
|
|
// Bit string for inspection
|
|
uint32_t bits = i;
|
|
|
|
// Get parity
|
|
if (tblParity[i]) {
|
|
bits |= (1 << 8);
|
|
}
|
|
|
|
#if SIGNAL_CONTROL_MODE == 1
|
|
// Negative logic is inverted
|
|
bits = ~bits;
|
|
#endif
|
|
|
|
// Create GPIO register information
|
|
uint32_t gpclr = 0;
|
|
uint32_t gpset = 0;
|
|
for (int j = 0; j < 9; j++) {
|
|
if (bits & 1) {
|
|
gpset |= (1 << pintbl[j]);
|
|
} else {
|
|
gpclr |= (1 << pintbl[j]);
|
|
}
|
|
bits >>= 1;
|
|
}
|
|
|
|
tblDatMsk[i] = gpclr;
|
|
tblDatSet[i] = gpset;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Wait for signal change
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
bool GPIOBUS::WaitSignal(board_type::pi_physical_pin_e pin, board_type::gpio_high_low_e ast)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
|
|
// Get current time
|
|
uint32_t now = SysTimer::GetTimerLow();
|
|
|
|
// Calculate timeout (3000ms)
|
|
uint32_t timeout = 3000 * 1000;
|
|
|
|
// end immediately if the signal has changed
|
|
do {
|
|
// Immediately upon receiving a reset
|
|
Acquire();
|
|
if (GetRST()) {
|
|
return false;
|
|
}
|
|
|
|
// Check for the signal edge
|
|
LOGWARN("THIS WONT WORK. NEEDS TO BE UPDATED");
|
|
|
|
if ((GetSignal(pin) ^ ~((int)(board->gpio_state_to_bool(ast)))) & 1) {
|
|
return true;
|
|
}
|
|
|
|
// if (((signals >> pin) ^ ~ast) & 1) {
|
|
// return true;
|
|
// }
|
|
} while ((SysTimer::GetTimerLow() - now) < timeout);
|
|
|
|
// We timed out waiting for the signal
|
|
return false;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Generic Phase Acquisition (Doesn't read GPIO)
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
BUS::phase_t GPIOBUS::GetPhaseRaw(uint32_t raw_data)
|
|
{
|
|
GPIO_FUNCTION_TRACE(void) raw_data;
|
|
// // Selection Phase
|
|
// if (GetPinRaw(raw_data, board->pin_sel)) {
|
|
// if (GetPinRaw(raw_data, board->pin_io)) {
|
|
// return BUS::phase_t::reselection;
|
|
// } else {
|
|
// return BUS::phase_t::selection;
|
|
// }
|
|
// }
|
|
|
|
// // Bus busy phase
|
|
// if (!GetPinRaw(raw_data, board->pin_bsy)) {
|
|
// return BUS::phase_t::busfree;
|
|
// }
|
|
|
|
LOGWARN("NOT IMPLEMENTED YET");
|
|
return BUS::phase_t::busfree;
|
|
// // Selection Phase
|
|
// if (GetSignal(board->pin_sel)) {
|
|
// if (GetSignal(board->pin_io)) {
|
|
// return BUS::phase_t::reselection;
|
|
// } else {
|
|
// return BUS::phase_t::selection;
|
|
// }
|
|
// }
|
|
|
|
// // Bus busy phase
|
|
// if (!GetPinRaw(raw_data, board->pin_bsy)) {
|
|
// return BUS::phase_t::busfree;
|
|
// }
|
|
|
|
// // Get target phase from bus signal line
|
|
// int mci = GetPinRaw(raw_data, board->pin_msg) ? 0x04 : 0x00;
|
|
// mci |= GetPinRaw(raw_data, board->pin_cd) ? 0x02 : 0x00;
|
|
// mci |= GetPinRaw(raw_data, board->pin_io) ? 0x01 : 0x00;
|
|
// return GetPhase(mci);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Get the number of bytes for a command
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
int GPIOBUS::GetCommandByteCount(BYTE opcode)
|
|
{
|
|
GPIO_FUNCTION_TRACE
|
|
|
|
if (opcode == 0x88 || opcode == 0x8A || opcode == 0x8F || opcode == 0x91 || opcode == 0x9E || opcode == 0x9F) {
|
|
return 16;
|
|
} else if (opcode == 0xA0) {
|
|
return 12;
|
|
} else if (opcode == 0x05 || (opcode >= 0x20 && opcode <= 0x7D)) {
|
|
return 10;
|
|
} else {
|
|
return 6;
|
|
}
|
|
}
|
|
|
|
const string GPIOBUS::GetConnectDesc()
|
|
{
|
|
if (board == nullptr) {
|
|
return "unknown";
|
|
}
|
|
return board->connect_desc;
|
|
}
|