36static constexpr uint8_t REG_BDID = 0;
37static constexpr uint8_t REG_SCTL = 1;
38static constexpr uint8_t REG_SCMD = 2;
39static constexpr uint8_t REG_OPEN = 3;
40static constexpr uint8_t REG_INTS = 4;
41static constexpr uint8_t REG_PSNS = 5;
42static constexpr uint8_t REG_SDGC = 5;
43static constexpr uint8_t REG_SSTS = 6;
44static constexpr uint8_t REG_SERR = 7;
45static constexpr uint8_t REG_PCTL = 8;
46static constexpr uint8_t REG_MBC = 9;
47static constexpr uint8_t REG_DREG = 10;
48static constexpr uint8_t REG_TEMP = 11;
51static constexpr uint8_t REG_TCH = 12;
52static constexpr uint8_t REG_TCM = 13;
53static constexpr uint8_t REG_TCL = 14;
55static constexpr uint8_t REG_TEMPWR = 13;
56static constexpr uint8_t FIX_PCTL = 14;
58static constexpr uint8_t PSNS_IO = 0x01;
59static constexpr uint8_t PSNS_CD = 0x02;
60static constexpr uint8_t PSNS_MSG = 0x04;
61static constexpr uint8_t PSNS_BSY = 0x08;
62static constexpr uint8_t PSNS_SEL = 0x10;
63static constexpr uint8_t PSNS_ATN = 0x20;
64static constexpr uint8_t PSNS_ACK = 0x40;
65static constexpr uint8_t PSNS_REQ = 0x80;
67static constexpr uint8_t PSNS_SELECTION = PSNS_SEL;
68static constexpr uint8_t PSNS_COMMAND = PSNS_CD;
69static constexpr uint8_t PSNS_DATAIN = PSNS_IO;
70static constexpr uint8_t PSNS_DATAOUT = 0;
71static constexpr uint8_t PSNS_STATUS = PSNS_CD | PSNS_IO;
72static constexpr uint8_t PSNS_MSGIN = PSNS_MSG | PSNS_CD | PSNS_IO;
73static constexpr uint8_t PSNS_MSGOUT = PSNS_MSG | PSNS_CD;
75static constexpr uint8_t INTS_ResetCondition = 0x01;
76static constexpr uint8_t INTS_SPC_HardError = 0x02;
77static constexpr uint8_t INTS_TimeOut = 0x04;
78static constexpr uint8_t INTS_ServiceRequited = 0x08;
79static constexpr uint8_t INTS_CommandComplete = 0x10;
80static constexpr uint8_t INTS_Disconnected = 0x20;
81static constexpr uint8_t INTS_ReSelected = 0x40;
82static constexpr uint8_t INTS_Selected = 0x80;
84static constexpr uint8_t CMD_BusRelease = 0x00;
85static constexpr uint8_t CMD_Select = 0x20;
86static constexpr uint8_t CMD_ResetATN = 0x40;
87static constexpr uint8_t CMD_SetATN = 0x60;
88static constexpr uint8_t CMD_Transfer = 0x80;
89static constexpr uint8_t CMD_TransferPause = 0xA0;
90static constexpr uint8_t CMD_Reset_ACK_REQ = 0xC0;
91static constexpr uint8_t CMD_Set_ACK_REQ = 0xE0;
92static constexpr uint8_t CMD_MASK = 0xE0;
101 unsigned id =
t->getAttributeValueAsInt(
"id", 0);
104 "Invalid SCSI id: ",
id,
105 " (should be 0..", MAX_DEV - 1,
')');
111 auto type =
t->getChildData(
"type");
112 if (type ==
"SCSIHD") {
113 dev[
id] = std::make_unique<SCSIHD>(conf, buffer,
115 }
else if (type ==
"SCSILS120") {
116 dev[
id] = std::make_unique<SCSILS120>(conf, buffer,
123 for (
auto& d : dev) {
124 if (!d) d = std::make_unique<DummySCSIDevice>();
132void MB89352::disconnect()
135 assert(targetId < MAX_DEV);
136 dev[targetId]->disconnect();
137 regs[REG_INTS] |= INTS_Disconnected;
150void MB89352::softReset()
154 for (
auto i :
xrange(2, 15)) {
168 regs[REG_BDID] = 0x80;
169 regs[REG_SCTL] = 0x80;
177 for (
const auto& d : dev) {
183void MB89352::setACKREQ(uint8_t& value)
186 if ((regs[REG_PSNS] & (PSNS_REQ | PSNS_BSY)) != (PSNS_REQ | PSNS_BSY)) {
188 if (regs[REG_PSNS] & PSNS_IO) {
195 if (regs[FIX_PCTL] != (regs[REG_PSNS] & 7)) {
197 if (regs[REG_PSNS] & PSNS_IO) {
201 regs[REG_INTS] |= INTS_ServiceRequited;
209 value = buffer[bufIdx];
211 regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_DATAIN;
215 buffer[bufIdx] = value;
217 regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_DATAOUT;
224 counter = (value < 0x20) ? 6 : ((value < 0xA0) ? 10 : 12);
228 regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_COMMAND;
232 value = dev[targetId]->getStatusCode();
233 regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_STATUS;
237 value = dev[targetId]->msgIn();
238 regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_MSGIN;
242 msgin |= dev[targetId]->msgOut(value);
243 regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_MSGOUT;
252void MB89352::resetACKREQ()
255 if ((regs[REG_PSNS] & (PSNS_ACK | PSNS_BSY)) != (PSNS_ACK | PSNS_BSY)) {
261 if (regs[FIX_PCTL] != (regs[REG_PSNS] & 7)) {
264 regs[REG_INTS] |= INTS_ServiceRequited;
273 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
275 if (blockCounter > 0) {
276 counter = narrow<int>(dev[targetId]->dataIn(blockCounter));
278 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
283 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
290 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
292 counter = narrow<int>(dev[targetId]->dataOut(blockCounter));
294 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
298 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
305 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_COMMAND;
309 counter = narrow<int>(dev[targetId]->executeCmd(cdb, phase, blockCounter));
312 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
315 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
318 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
321 regs[REG_PSNS] = PSNS_BSY;
332 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGIN;
354 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGOUT;
374 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_COMMAND;
377 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
380 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
383 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
386 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGIN;
403 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGOUT;
409 if (isTransfer && (tc > 0)) {
410 setACKREQ(regs[REG_DREG]);
416 regs[REG_INTS] |= INTS_CommandComplete;
418 regs[REG_MBC] = (regs[REG_MBC] - 1) & 0x0F;
419 return regs[REG_DREG];
427 if (isTransfer && (tc > 0)) {
434 regs[REG_INTS] |= INTS_CommandComplete;
436 regs[REG_MBC] = (regs[REG_MBC] - 1) & 0x0F;
454 if (((regs[REG_SCMD] & 0x10) == 0) && (regs[REG_SCTL] == 0)) {
456 regs[REG_INTS] |= INTS_ResetCondition;
457 for (
const auto& d : dev) {
466 regs[REG_SCMD] = value;
470 switch (value & CMD_MASK) {
471 case CMD_Set_ACK_REQ:
476 setACKREQ(regs[REG_TEMP]);
479 setACKREQ(regs[REG_TEMPWR]);
483 case CMD_Reset_ACK_REQ:
489 regs[REG_INTS] |= INTS_TimeOut;
493 if (regs[REG_PCTL] & 1) {
495 regs[REG_INTS] |= INTS_TimeOut;
500 int x = regs[REG_BDID] & regs[REG_TEMPWR];
501 if (phase == BUS_FREE && x && x != regs[REG_TEMPWR]) {
502 x = regs[REG_TEMPWR] & ~regs[REG_BDID];
512 assert(targetId < MAX_DEV);
515 if ( dev[targetId]->isSelected()) {
517 regs[REG_INTS] |= INTS_CommandComplete;
525 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGOUT;
528 nextPhase = UNDEFINED;
529 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_COMMAND;
540 regs[REG_INTS] |= INTS_TimeOut;
547 if ((regs[FIX_PCTL] == (regs[REG_PSNS] & 7)) &&
548 (regs[REG_PSNS] & (PSNS_REQ | PSNS_BSY))) {
552 regs[REG_INTS] |= INTS_ServiceRequited;
568 case CMD_TransferPause:
575 regs[REG_INTS] &= ~value;
577 regs[REG_INTS] |= INTS_ResetCondition;
582 regs[REG_TEMPWR] = value;
586 tc = (tc & 0xFFFF00) + (value << 0);
590 tc = (tc & 0xFF00FF) + (value << 8);
594 tc = (tc & 0x00FFFF) + (value << 16);
598 regs[REG_PCTL] = value;
599 regs[FIX_PCTL] = value & 7;
606 regs[REG_BDID] = uint8_t(1 << value);
618 if (
bool flag = !(value & 0xE0); flag != isEnabled) {
631uint8_t MB89352::getSSTS()
const
634 if (isTransfer && (regs[REG_PSNS] & PSNS_IO)) {
669 if (phase == EXECUTE) {
670 counter = narrow<int>(dev[targetId]->executingCmd(phase, blockCounter));
671 if (atn && phase != EXECUTE) {
674 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGOUT;
678 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
681 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
684 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
687 regs[REG_PSNS] = PSNS_BSY;
695 return regs[REG_PSNS] | atn;
704 if (isTransfer && (tc > 0)) {
705 return regs[REG_DREG];
717 return regs[REG_PSNS] | atn;
721 return narrow_cast<uint8_t>((tc >> 16) & 0xFF);
723 return narrow_cast<uint8_t>((tc >> 8) & 0xFF);
725 return narrow_cast<uint8_t>((tc >> 0) & 0xFF);
733static constexpr std::initializer_list<enum_string<SCSI::Phase>> phaseInfo = {
749template<
typename Archive>
752 ar.serialize_blob(
"buffer", buffer);
753 std::array<char, 8> tag = {
'd',
'e',
'v',
'i',
'c',
'e',
'X', 0};
755 tag[6] = char(
'0' + i);
756 ar.serializePolymorphic(tag.data(), *d);
758 ar.serialize(
"bufIdx", bufIdx,
761 "blockCounter", blockCounter,
764 "nextPhase", nextPhase,
766 "targetId", targetId);
767 ar.serialize_blob(
"registers", regs);
768 ar.serialize(
"rst", rst,
770 "isEnabled", isEnabled,
772 "isTransfer", isTransfer,
774 ar.serialize_blob(
"cdb", cdb);
const XMLElement * getXML() const
uint8_t peekRegister(uint8_t reg) const
void reset(bool scsiReset)
void writeRegister(uint8_t reg, uint8_t value)
uint8_t readRegister(uint8_t reg)
void serialize(Archive &ar, unsigned version)
void writeDREG(uint8_t value)
MB89352(const DeviceConfig &config)
static constexpr unsigned MODE_MEGASCSI
static constexpr unsigned MODE_SCSI2
ChildRange getChildren() const
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
This file implemented 3 utility functions:
constexpr void fill(ForwardRange &&range, const T &value)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
#define SERIALIZE_ENUM(TYPE, INFO)
constexpr auto xrange(T e)