35static constexpr unsigned MAX_DEV = 8;
37static constexpr uint8_t REG_OWN_ID = 0x00;
38static constexpr uint8_t REG_CONTROL = 0x01;
39static constexpr uint8_t REG_TIMEO = 0x02;
40static constexpr uint8_t REG_TSECS = 0x03;
41static constexpr uint8_t REG_THEADS = 0x04;
42static constexpr uint8_t REG_TCYL_HI = 0x05;
43static constexpr uint8_t REG_TCYL_LO = 0x06;
44static constexpr uint8_t REG_ADDR_HI = 0x07;
45static constexpr uint8_t REG_ADDR_2 = 0x08;
46static constexpr uint8_t REG_ADDR_3 = 0x09;
47static constexpr uint8_t REG_ADDR_LO = 0x0a;
48static constexpr uint8_t REG_SECNO = 0x0b;
49static constexpr uint8_t REG_HEADNO = 0x0c;
50static constexpr uint8_t REG_CYLNO_HI = 0x0d;
51static constexpr uint8_t REG_CYLNO_LO = 0x0e;
52static constexpr uint8_t REG_TLUN = 0x0f;
53static constexpr uint8_t REG_CMD_PHASE = 0x10;
54static constexpr uint8_t REG_SYN = 0x11;
55static constexpr uint8_t REG_TCH = 0x12;
56static constexpr uint8_t REG_TCM = 0x13;
57static constexpr uint8_t REG_TCL = 0x14;
58static constexpr uint8_t REG_DST_ID = 0x15;
59static constexpr uint8_t REG_SRC_ID = 0x16;
60static constexpr uint8_t REG_SCSI_STATUS = 0x17;
61static constexpr uint8_t REG_CMD = 0x18;
62static constexpr uint8_t REG_DATA = 0x19;
63static constexpr uint8_t REG_QUEUE_TAG = 0x1a;
64static constexpr uint8_t REG_AUX_STATUS = 0x1f;
66static constexpr uint8_t REG_CDBSIZE = 0x00;
67static constexpr uint8_t REG_CDB1 = 0x03;
68static constexpr uint8_t REG_CDB2 = 0x04;
69static constexpr uint8_t REG_CDB3 = 0x05;
70static constexpr uint8_t REG_CDB4 = 0x06;
71static constexpr uint8_t REG_CDB5 = 0x07;
72static constexpr uint8_t REG_CDB6 = 0x08;
73static constexpr uint8_t REG_CDB7 = 0x09;
74static constexpr uint8_t REG_CDB8 = 0x0a;
75static constexpr uint8_t REG_CDB9 = 0x0b;
76static constexpr uint8_t REG_CDB10 = 0x0c;
77static constexpr uint8_t REG_CDB11 = 0x0d;
78static constexpr uint8_t REG_CDB12 = 0x0e;
80static constexpr uint8_t OWN_EAF = 0x08;
83static constexpr uint8_t SS_RESET = 0x00;
84static constexpr uint8_t SS_RESET_ADV = 0x01;
85static constexpr uint8_t SS_XFER_END = 0x16;
86static constexpr uint8_t SS_SEL_TIMEOUT = 0x42;
87static constexpr uint8_t SS_DISCONNECT = 0x85;
90static constexpr uint8_t AS_DBR = 0x01;
91static constexpr uint8_t AS_CIP = 0x10;
92static constexpr uint8_t AS_BSY = 0x20;
93static constexpr uint8_t AS_LCI = 0x40;
94static constexpr uint8_t AS_INT = 0x80;
115 unsigned id =
t->getAttributeValueAsInt(
"id", 0);
118 " (should be 0..", MAX_DEV - 1,
')');
124 auto type =
t->getChildData(
"type");
125 if (type ==
"SCSIHD") {
126 dev[
id] = std::make_unique<SCSIHD>(conf, buffer,
129 }
else if (type ==
"SCSILS120") {
130 dev[
id] = std::make_unique<SCSILS120>(conf, buffer,
138 for (
auto& d : dev) {
139 if (!d) d = std::make_unique<DummySCSIDevice>();
147void WD33C93::disconnect()
150 assert(targetId < MAX_DEV);
151 dev[targetId]->disconnect();
152 if (regs[REG_SCSI_STATUS] != SS_XFER_END) {
153 regs[REG_SCSI_STATUS] = SS_DISCONNECT;
155 regs[REG_AUX_STATUS] = AS_INT;
161void WD33C93::execCmd(uint8_t value)
163 if (regs[REG_AUX_STATUS] & AS_CIP) {
168 regs[REG_CMD] = value;
176 regs[REG_SCSI_STATUS] =
177 (regs[REG_OWN_ID] & OWN_EAF) ? SS_RESET_ADV : SS_RESET;
191 targetId = regs[REG_DST_ID] & 7;
192 regs[REG_SCSI_STATUS] = SS_SEL_TIMEOUT;
194 regs[REG_AUX_STATUS] = AS_INT;
201 targetId = regs[REG_DST_ID] & 7;
203 if (!devBusy && targetId < MAX_DEV &&
204 dev[targetId]->isSelected()) {
206 dev[targetId]->msgOut(regs[REG_TLUN] | 0x80);
209 counter = dev[targetId]->executeCmd(
210 subspan<12>(regs, REG_CDB1), phase, blockCounter);
215 regs[REG_TLUN] = dev[targetId]->getStatusCode();
216 dev[targetId]->msgIn();
217 regs[REG_SCSI_STATUS] = SS_XFER_END;
222 regs[REG_AUX_STATUS] = AS_CIP | AS_BSY;
228 regs[REG_AUX_STATUS] = AS_CIP | AS_BSY | AS_DBR;
235 regs[REG_SCSI_STATUS] = SS_SEL_TIMEOUT;
236 regs[REG_AUX_STATUS] = AS_INT;
249 latch = value & 0x1f;
258 regs[REG_OWN_ID] = value;
263 tc = (tc & 0x00ffff) + (value << 16);
267 tc = (tc & 0xff00ff) + (value << 8);
271 tc = (tc & 0xffff00) + (value << 0);
275 regs[REG_CMD_PHASE] = value;
283 regs[REG_DATA] = value;
285 buffer[bufIdx++] = value;
287 if (--counter == 0) {
288 counter = dev[targetId]->dataOut(blockCounter);
293 regs[REG_TLUN] = dev[targetId]->getStatusCode();
294 dev[targetId]->msgIn();
295 regs[REG_SCSI_STATUS] = SS_XFER_END;
305 if (latch <= REG_SRC_ID) {
310 latch = (latch + 1) & 0x1f;
315 uint8_t rv = regs[REG_AUX_STATUS];
318 counter = dev[targetId]->executingCmd(phase, blockCounter);
322 regs[REG_TLUN] = dev[targetId]->getStatusCode();
323 dev[targetId]->msgIn();
324 regs[REG_SCSI_STATUS] = SS_XFER_END;
332 regs[REG_AUX_STATUS] |= AS_DBR;
344 case REG_SCSI_STATUS:
345 rv = regs[REG_SCSI_STATUS];
346 if (rv != SS_XFER_END) {
347 regs[REG_AUX_STATUS] &= ~AS_INT;
349 regs[REG_SCSI_STATUS] = SS_DISCONNECT;
350 regs[REG_AUX_STATUS] = AS_INT;
355 return regs[REG_CMD];
359 rv = buffer[bufIdx++];
362 if (--counter == 0) {
363 if (blockCounter > 0) {
364 counter = dev[targetId]->dataIn(blockCounter);
370 regs[REG_TLUN] = dev[targetId]->getStatusCode();
371 dev[targetId]->msgIn();
372 regs[REG_SCSI_STATUS] = SS_XFER_END;
381 rv = narrow_cast<uint8_t>((tc >> 16) & 0xff);
385 rv = narrow_cast<uint8_t>((tc >> 8) & 0xff);
389 rv = narrow_cast<uint8_t>((tc >> 0) & 0xff);
400 latch = (latch + 1) & 0x1f;
406 return regs[REG_AUX_STATUS];
413 return narrow_cast<uint8_t>((tc >> 16) & 0xff);
415 return narrow_cast<uint8_t>((tc >> 8) & 0xff);
417 return narrow_cast<uint8_t>((tc >> 0) & 0xff);
428 regs[REG_AUX_STATUS] = AS_INT;
435 for (
const auto& d : dev) {
442static constexpr std::initializer_list<enum_string<SCSI::Phase>> phaseInfo = {
458template<
typename Archive>
461 ar.serialize_blob(
"buffer", buffer);
462 std::array<char, 8> tag = {
'd',
'e',
'v',
'i',
'c',
'e',
'X', 0};
464 tag[6] = char(
'0' + i);
465 ar.serializePolymorphic(tag.data(), *d);
467 ar.serialize(
"bufIdx", bufIdx,
469 "blockCounter", blockCounter,
473 "targetId", targetId);
474 ar.serialize_blob(
"registers", regs);
475 ar.serialize(
"latch", latch,
const XMLElement * getXML() const
static constexpr unsigned MODE_NOVAXIS
static constexpr unsigned MODE_SCSI1
static constexpr unsigned MODE_UNITATTENTION
void serialize(Archive &ar, unsigned version)
void reset(bool scsiReset)
void writeAdr(uint8_t value)
WD33C93(const DeviceConfig &config)
uint8_t peekAuxStatus() const
void writeCtrl(uint8_t value)
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)