32static constexpr uint8_t REG_BDID = 0;
33static constexpr uint8_t REG_SCTL = 1;
34static constexpr uint8_t REG_SCMD = 2;
35static constexpr uint8_t REG_OPEN = 3;
36static constexpr uint8_t REG_INTS = 4;
37static constexpr uint8_t REG_PSNS = 5;
38static constexpr uint8_t REG_SDGC = 5;
39static constexpr uint8_t REG_SSTS = 6;
40static constexpr uint8_t REG_SERR = 7;
41static constexpr uint8_t REG_PCTL = 8;
42static constexpr uint8_t REG_MBC = 9;
43static constexpr uint8_t REG_DREG = 10;
44static constexpr uint8_t REG_TEMP = 11;
47static constexpr uint8_t REG_TCH = 12;
48static constexpr uint8_t REG_TCM = 13;
49static constexpr uint8_t REG_TCL = 14;
51static constexpr uint8_t REG_TEMPWR = 13;
52static constexpr uint8_t FIX_PCTL = 14;
54static constexpr uint8_t PSNS_IO = 0x01;
55static constexpr uint8_t PSNS_CD = 0x02;
56static constexpr uint8_t PSNS_MSG = 0x04;
57static constexpr uint8_t PSNS_BSY = 0x08;
58static constexpr uint8_t PSNS_SEL = 0x10;
59static constexpr uint8_t PSNS_ATN = 0x20;
60static constexpr uint8_t PSNS_ACK = 0x40;
61static constexpr uint8_t PSNS_REQ = 0x80;
63static constexpr uint8_t PSNS_SELECTION = PSNS_SEL;
64static constexpr uint8_t PSNS_COMMAND = PSNS_CD;
65static constexpr uint8_t PSNS_DATAIN = PSNS_IO;
66static constexpr uint8_t PSNS_DATAOUT = 0;
67static constexpr uint8_t PSNS_STATUS = PSNS_CD | PSNS_IO;
68static constexpr uint8_t PSNS_MSGIN = PSNS_MSG | PSNS_CD | PSNS_IO;
69static constexpr uint8_t PSNS_MSGOUT = PSNS_MSG | PSNS_CD;
71static constexpr uint8_t INTS_ResetCondition = 0x01;
72static constexpr uint8_t INTS_SPC_HardError = 0x02;
73static constexpr uint8_t INTS_TimeOut = 0x04;
74static constexpr uint8_t INTS_ServiceRequited = 0x08;
75static constexpr uint8_t INTS_CommandComplete = 0x10;
76static constexpr uint8_t INTS_Disconnected = 0x20;
77static constexpr uint8_t INTS_ReSelected = 0x40;
78static constexpr uint8_t INTS_Selected = 0x80;
80static constexpr uint8_t CMD_BusRelease = 0x00;
81static constexpr uint8_t CMD_Select = 0x20;
82static constexpr uint8_t CMD_ResetATN = 0x40;
83static constexpr uint8_t CMD_SetATN = 0x60;
84static constexpr uint8_t CMD_Transfer = 0x80;
85static constexpr uint8_t CMD_TransferPause = 0xA0;
86static constexpr uint8_t CMD_Reset_ACK_REQ = 0xC0;
87static constexpr uint8_t CMD_Set_ACK_REQ = 0xE0;
88static constexpr uint8_t CMD_MASK = 0xE0;
97 unsigned id =
t->getAttributeValueAsInt(
"id", 0);
100 "Invalid SCSI id: ",
id,
101 " (should be 0..", MAX_DEV - 1,
')');
107 auto type =
t->getChildData(
"type");
108 if (type ==
"SCSIHD") {
109 dev[
id] = std::make_unique<SCSIHD>(conf, buffer,
111 }
else if (type ==
"SCSILS120") {
112 dev[
id] = std::make_unique<SCSILS120>(conf, buffer,
119 for (
auto& d : dev) {
120 if (!d) d = std::make_unique<DummySCSIDevice>();
128void MB89352::disconnect()
131 assert(targetId < MAX_DEV);
132 dev[targetId]->disconnect();
133 regs[REG_INTS] |= INTS_Disconnected;
146void MB89352::softReset()
150 for (
auto i :
xrange(2, 15)) {
164 regs[REG_BDID] = 0x80;
165 regs[REG_SCTL] = 0x80;
173 for (
auto& d : dev) {
179void MB89352::setACKREQ(uint8_t& value)
182 if ((regs[REG_PSNS] & (PSNS_REQ | PSNS_BSY)) != (PSNS_REQ | PSNS_BSY)) {
184 if (regs[REG_PSNS] & PSNS_IO) {
191 if (regs[FIX_PCTL] != (regs[REG_PSNS] & 7)) {
193 if (regs[REG_PSNS] & PSNS_IO) {
197 regs[REG_INTS] |= INTS_ServiceRequited;
204 value = buffer[bufIdx];
206 regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_DATAIN;
210 buffer[bufIdx] = value;
212 regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_DATAOUT;
219 counter = (value < 0x20) ? 6 : ((value < 0xA0) ? 10 : 12);
223 regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_COMMAND;
227 value = dev[targetId]->getStatusCode();
228 regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_STATUS;
232 value = dev[targetId]->msgIn();
233 regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_MSGIN;
237 msgin |= dev[targetId]->msgOut(value);
238 regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_MSGOUT;
247void MB89352::resetACKREQ()
250 if ((regs[REG_PSNS] & (PSNS_ACK | PSNS_BSY)) != (PSNS_ACK | PSNS_BSY)) {
256 if (regs[FIX_PCTL] != (regs[REG_PSNS] & 7)) {
259 regs[REG_INTS] |= INTS_ServiceRequited;
267 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
269 if (blockCounter > 0) {
270 counter = narrow<int>(dev[targetId]->dataIn(blockCounter));
272 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
277 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
284 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
286 counter = narrow<int>(dev[targetId]->dataOut(blockCounter));
288 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
292 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
299 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_COMMAND;
303 counter = narrow<int>(dev[targetId]->executeCmd(cdb, phase, blockCounter));
306 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
309 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
312 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
315 regs[REG_PSNS] = PSNS_BSY;
326 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGIN;
348 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGOUT;
368 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_COMMAND;
371 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
374 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
377 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
380 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGIN;
397 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGOUT;
403 if (isTransfer && (tc > 0)) {
404 setACKREQ(regs[REG_DREG]);
410 regs[REG_INTS] |= INTS_CommandComplete;
412 regs[REG_MBC] = (regs[REG_MBC] - 1) & 0x0F;
413 return regs[REG_DREG];
421 if (isTransfer && (tc > 0)) {
428 regs[REG_INTS] |= INTS_CommandComplete;
430 regs[REG_MBC] = (regs[REG_MBC] - 1) & 0x0F;
448 if (((regs[REG_SCMD] & 0x10) == 0) && (regs[REG_SCTL] == 0)) {
450 regs[REG_INTS] |= INTS_ResetCondition;
451 for (
auto& d : dev) {
460 regs[REG_SCMD] = value;
463 switch (value & CMD_MASK) {
464 case CMD_Set_ACK_REQ:
469 setACKREQ(regs[REG_TEMP]);
472 setACKREQ(regs[REG_TEMPWR]);
476 case CMD_Reset_ACK_REQ:
482 regs[REG_INTS] |= INTS_TimeOut;
486 if (regs[REG_PCTL] & 1) {
488 regs[REG_INTS] |= INTS_TimeOut;
493 int x = regs[REG_BDID] & regs[REG_TEMPWR];
495 x = regs[REG_TEMPWR] & ~regs[REG_BDID];
505 assert(targetId < MAX_DEV);
508 if ( dev[targetId]->isSelected()) {
510 regs[REG_INTS] |= INTS_CommandComplete;
518 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGOUT;
522 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_COMMAND;
533 regs[REG_INTS] |= INTS_TimeOut;
540 if ((regs[FIX_PCTL] == (regs[REG_PSNS] & 7)) &&
541 (regs[REG_PSNS] & (PSNS_REQ | PSNS_BSY))) {
545 regs[REG_INTS] |= INTS_ServiceRequited;
561 case CMD_TransferPause:
568 regs[REG_INTS] &= ~value;
570 regs[REG_INTS] |= INTS_ResetCondition;
575 regs[REG_TEMPWR] = value;
579 tc = (tc & 0xFFFF00) + (value << 0);
583 tc = (tc & 0xFF00FF) + (value << 8);
587 tc = (tc & 0x00FFFF) + (value << 16);
591 regs[REG_PCTL] = value;
592 regs[FIX_PCTL] = value & 7;
599 regs[REG_BDID] = uint8_t(1 << value);
611 bool flag = !(value & 0xE0);
612 if (flag != isEnabled) {
625uint8_t MB89352::getSSTS()
const
629 if (regs[REG_PSNS] & PSNS_IO) {
665 counter = narrow<int>(dev[targetId]->executingCmd(phase, blockCounter));
669 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGOUT;
673 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
676 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
679 regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
682 regs[REG_PSNS] = PSNS_BSY;
690 return regs[REG_PSNS] | atn;
699 if (isTransfer && (tc > 0)) {
700 return regs[REG_DREG];
712 return regs[REG_PSNS] | atn;
716 return narrow_cast<uint8_t>((tc >> 16) & 0xFF);
718 return narrow_cast<uint8_t>((tc >> 8) & 0xFF);
720 return narrow_cast<uint8_t>((tc >> 0) & 0xFF);
728static constexpr std::initializer_list<enum_string<SCSI::Phase>> phaseInfo = {
744template<
typename Archive>
747 ar.serialize_blob(
"buffer", buffer);
748 std::array<char, 8> tag = {
'd',
'e',
'v',
'i',
'c',
'e',
'X', 0};
750 tag[6] = char(
'0' + i);
751 ar.serializePolymorphic(tag.data(), *d);
753 ar.serialize(
"bufIdx", bufIdx,
756 "blockCounter", blockCounter,
759 "nextPhase", nextPhase,
761 "targetId", targetId);
762 ar.serialize_blob(
"registers", regs);
763 ar.serialize(
"rst", rst,
765 "isEnabled", isEnabled,
767 "isTransfer", isTransfer,
769 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:
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
constexpr void fill(ForwardRange &&range, const T &value)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)