31static constexpr unsigned MAX_DEV = 8;
33static constexpr uint8_t REG_OWN_ID = 0x00;
34static constexpr uint8_t REG_CONTROL = 0x01;
35static constexpr uint8_t REG_TIMEO = 0x02;
36static constexpr uint8_t REG_TSECS = 0x03;
37static constexpr uint8_t REG_THEADS = 0x04;
38static constexpr uint8_t REG_TCYL_HI = 0x05;
39static constexpr uint8_t REG_TCYL_LO = 0x06;
40static constexpr uint8_t REG_ADDR_HI = 0x07;
41static constexpr uint8_t REG_ADDR_2 = 0x08;
42static constexpr uint8_t REG_ADDR_3 = 0x09;
43static constexpr uint8_t REG_ADDR_LO = 0x0a;
44static constexpr uint8_t REG_SECNO = 0x0b;
45static constexpr uint8_t REG_HEADNO = 0x0c;
46static constexpr uint8_t REG_CYLNO_HI = 0x0d;
47static constexpr uint8_t REG_CYLNO_LO = 0x0e;
48static constexpr uint8_t REG_TLUN = 0x0f;
49static constexpr uint8_t REG_CMD_PHASE = 0x10;
50static constexpr uint8_t REG_SYN = 0x11;
51static constexpr uint8_t REG_TCH = 0x12;
52static constexpr uint8_t REG_TCM = 0x13;
53static constexpr uint8_t REG_TCL = 0x14;
54static constexpr uint8_t REG_DST_ID = 0x15;
55static constexpr uint8_t REG_SRC_ID = 0x16;
56static constexpr uint8_t REG_SCSI_STATUS = 0x17;
57static constexpr uint8_t REG_CMD = 0x18;
58static constexpr uint8_t REG_DATA = 0x19;
59static constexpr uint8_t REG_QUEUE_TAG = 0x1a;
60static constexpr uint8_t REG_AUX_STATUS = 0x1f;
62static constexpr uint8_t REG_CDBSIZE = 0x00;
63static constexpr uint8_t REG_CDB1 = 0x03;
64static constexpr uint8_t REG_CDB2 = 0x04;
65static constexpr uint8_t REG_CDB3 = 0x05;
66static constexpr uint8_t REG_CDB4 = 0x06;
67static constexpr uint8_t REG_CDB5 = 0x07;
68static constexpr uint8_t REG_CDB6 = 0x08;
69static constexpr uint8_t REG_CDB7 = 0x09;
70static constexpr uint8_t REG_CDB8 = 0x0a;
71static constexpr uint8_t REG_CDB9 = 0x0b;
72static constexpr uint8_t REG_CDB10 = 0x0c;
73static constexpr uint8_t REG_CDB11 = 0x0d;
74static constexpr uint8_t REG_CDB12 = 0x0e;
76static constexpr uint8_t OWN_EAF = 0x08;
79static constexpr uint8_t SS_RESET = 0x00;
80static constexpr uint8_t SS_RESET_ADV = 0x01;
81static constexpr uint8_t SS_XFER_END = 0x16;
82static constexpr uint8_t SS_SEL_TIMEOUT = 0x42;
83static constexpr uint8_t SS_DISCONNECT = 0x85;
86static constexpr uint8_t AS_DBR = 0x01;
87static constexpr uint8_t AS_CIP = 0x10;
88static constexpr uint8_t AS_BSY = 0x20;
89static constexpr uint8_t AS_LCI = 0x40;
90static constexpr uint8_t AS_INT = 0x80;
111 unsigned id =
t->getAttributeValueAsInt(
"id", 0);
114 " (should be 0..", MAX_DEV - 1,
')');
120 auto type =
t->getChildData(
"type");
121 if (type ==
"SCSIHD") {
122 dev[
id] = std::make_unique<SCSIHD>(conf, buffer,
125 }
else if (type ==
"SCSILS120") {
126 dev[
id] = std::make_unique<SCSILS120>(conf, buffer,
134 for (
auto& d : dev) {
135 if (!d) d = std::make_unique<DummySCSIDevice>();
143void WD33C93::disconnect()
146 assert(targetId < MAX_DEV);
147 dev[targetId]->disconnect();
148 if (regs[REG_SCSI_STATUS] != SS_XFER_END) {
149 regs[REG_SCSI_STATUS] = SS_DISCONNECT;
151 regs[REG_AUX_STATUS] = AS_INT;
157void WD33C93::execCmd(uint8_t value)
159 if (regs[REG_AUX_STATUS] & AS_CIP) {
164 regs[REG_CMD] = value;
172 regs[REG_SCSI_STATUS] =
173 (regs[REG_OWN_ID] & OWN_EAF) ? SS_RESET_ADV : SS_RESET;
187 targetId = regs[REG_DST_ID] & 7;
188 regs[REG_SCSI_STATUS] = SS_SEL_TIMEOUT;
190 regs[REG_AUX_STATUS] = AS_INT;
197 targetId = regs[REG_DST_ID] & 7;
199 if (!devBusy && targetId < MAX_DEV &&
200 dev[targetId]->isSelected()) {
202 dev[targetId]->msgOut(regs[REG_TLUN] | 0x80);
205 counter = dev[targetId]->executeCmd(
206 subspan<12>(regs, REG_CDB1), phase, blockCounter);
211 regs[REG_TLUN] = dev[targetId]->getStatusCode();
212 dev[targetId]->msgIn();
213 regs[REG_SCSI_STATUS] = SS_XFER_END;
218 regs[REG_AUX_STATUS] = AS_CIP | AS_BSY;
224 regs[REG_AUX_STATUS] = AS_CIP | AS_BSY | AS_DBR;
231 regs[REG_SCSI_STATUS] = SS_SEL_TIMEOUT;
232 regs[REG_AUX_STATUS] = AS_INT;
245 latch = value & 0x1f;
254 regs[REG_OWN_ID] = value;
259 tc = (tc & 0x00ffff) + (value << 16);
263 tc = (tc & 0xff00ff) + (value << 8);
267 tc = (tc & 0xffff00) + (value << 0);
271 regs[REG_CMD_PHASE] = value;
279 regs[REG_DATA] = value;
281 buffer[bufIdx++] = value;
283 if (--counter == 0) {
284 counter = dev[targetId]->dataOut(blockCounter);
289 regs[REG_TLUN] = dev[targetId]->getStatusCode();
290 dev[targetId]->msgIn();
291 regs[REG_SCSI_STATUS] = SS_XFER_END;
301 if (latch <= REG_SRC_ID) {
306 latch = (latch + 1) & 0x1f;
311 uint8_t rv = regs[REG_AUX_STATUS];
314 counter = dev[targetId]->executingCmd(phase, blockCounter);
318 regs[REG_TLUN] = dev[targetId]->getStatusCode();
319 dev[targetId]->msgIn();
320 regs[REG_SCSI_STATUS] = SS_XFER_END;
328 regs[REG_AUX_STATUS] |= AS_DBR;
340 case REG_SCSI_STATUS:
341 rv = regs[REG_SCSI_STATUS];
342 if (rv != SS_XFER_END) {
343 regs[REG_AUX_STATUS] &= ~AS_INT;
345 regs[REG_SCSI_STATUS] = SS_DISCONNECT;
346 regs[REG_AUX_STATUS] = AS_INT;
351 return regs[REG_CMD];
355 rv = buffer[bufIdx++];
358 if (--counter == 0) {
359 if (blockCounter > 0) {
360 counter = dev[targetId]->dataIn(blockCounter);
366 regs[REG_TLUN] = dev[targetId]->getStatusCode();
367 dev[targetId]->msgIn();
368 regs[REG_SCSI_STATUS] = SS_XFER_END;
377 rv = narrow_cast<uint8_t>((tc >> 16) & 0xff);
381 rv = narrow_cast<uint8_t>((tc >> 8) & 0xff);
385 rv = narrow_cast<uint8_t>((tc >> 0) & 0xff);
396 latch = (latch + 1) & 0x1f;
402 return regs[REG_AUX_STATUS];
409 return narrow_cast<uint8_t>((tc >> 16) & 0xff);
411 return narrow_cast<uint8_t>((tc >> 8) & 0xff);
413 return narrow_cast<uint8_t>((tc >> 0) & 0xff);
424 regs[REG_AUX_STATUS] = AS_INT;
431 for (
auto& d : dev) {
438static constexpr std::initializer_list<enum_string<SCSI::Phase>> phaseInfo = {
454template<
typename Archive>
457 ar.serialize_blob(
"buffer", buffer);
458 std::array<char, 8> tag = {
'd',
'e',
'v',
'i',
'c',
'e',
'X', 0};
460 tag[6] = char(
'0' + i);
461 ar.serializePolymorphic(tag.data(), *d);
463 ar.serialize(
"bufIdx", bufIdx,
465 "blockCounter", blockCounter,
469 "targetId", targetId);
470 ar.serialize_blob(
"registers", regs);
471 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:
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
constexpr void fill(ForwardRange &&range, const T &value)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)