Skip to content

Commit 5789c2e

Browse files
committed
SCSI running commands
1 parent 870adbc commit 5789c2e

3 files changed

Lines changed: 147 additions & 35 deletions

File tree

src/cdrom.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ u8 CdRom::ReadRegister(u16 address)
5454
return m_scsi_controller->GetStatus();
5555
case 0x01:
5656
// SCSI get data
57-
Debug("CDROM Read SCSI get data %02X", reg);
57+
//Debug("CDROM Read SCSI get data %02X", reg);
5858
return m_scsi_controller->ReadData();
5959
case 0x02:
6060
// IRQs
@@ -125,7 +125,7 @@ void CdRom::WriteRegister(u16 address, u8 value)
125125
break;
126126
case 0x01:
127127
// SCSI command
128-
Debug("CDROM Write SCSI command %02X, value: %02X", reg, value);
128+
//Debug("CDROM Write SCSI command %02X, value: %02X", reg, value);
129129
m_scsi_controller->WriteData(value);
130130
m_scsi_controller->BusChange();
131131
break;

src/scsi_controller.cpp

Lines changed: 107 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ ScsiController::ScsiController(CdRomMedia* cdrom_media)
2727
m_bus.db = 0;
2828
m_bus.signals = 0;
2929
m_command_buffer.clear();
30-
m_command_buffer.resize(16);
30+
m_command_buffer.reserve(16);
31+
m_data_buffer.clear();
32+
m_data_buffer.reserve(8192);
33+
m_data_buffer_offset = 0;
3134
m_read_current_lba = 0;
3235
m_read_sectors_remaining = 0;
3336
m_read_sector_offset = 0;
@@ -48,6 +51,8 @@ void ScsiController::Reset()
4851
m_bus.db = 0;
4952
m_bus.signals = 0;
5053
m_command_buffer.clear();
54+
m_data_buffer.clear();
55+
m_data_buffer_offset = 0;
5156
m_read_current_lba = 0;
5257
m_read_sectors_remaining = 0;
5358
m_read_sector_offset = 0;
@@ -63,25 +68,49 @@ void ScsiController::Clock(u32 cycles)
6368
switch (m_next_event)
6469
{
6570
case SCSI_EVENT_SET_COMMAND_PHASE:
66-
Debug("SCSI Set command phase");
71+
Debug("SCSI Event Set command phase");
6772
SetEvent(SCSI_EVENT_NONE, 0);
6873
SetPhase(SCSI_PHASE_COMMAND);
6974
break;
7075
case SCSI_EVENT_SET_REQ_SIGNAL:
71-
Debug("SCSI Set REQ signal");
76+
Debug("SCSI Event Set REQ signal");
7277
SetEvent(SCSI_EVENT_NONE, 0);
7378
SetSignal(SCSI_SIGNAL_REQ);
7479
break;
80+
case SCSI_SET_GOOD_STATUS:
81+
Debug("SCSI Event Set good status");
82+
SetEvent(SCSI_EVENT_NONE, 0);
83+
StartStatus(SCSI_STATUS_GOOD);
84+
break;
7585
default:
7686
break;
7787
}
7888
}
7989
}
8090
}
8191

92+
u8 ScsiController::ReadData()
93+
{
94+
Debug("SCSI Read data: %02X", m_bus.db);
95+
return m_bus.db;
96+
}
97+
98+
void ScsiController::WriteData(u8 value)
99+
{
100+
Debug("SCSI Write data: %02X", value);
101+
m_bus.db = value;
102+
}
103+
104+
u8 ScsiController::GetStatus()
105+
{
106+
return (m_bus.signals & 0xF8);
107+
}
108+
82109
void ScsiController::SetPhase(ScsiPhase phase)
83110
{
84-
Debug("SCSI Set phase %d", phase);
111+
Debug("----------------");
112+
Debug("SCSI Set phase %s", k_scsi_phase_names[phase]);
113+
Debug("----------------");
85114

86115
if (m_phase == phase)
87116
return;
@@ -116,19 +145,9 @@ void ScsiController::SetEvent(ScsiEvent event, u32 cycles)
116145
m_next_event_cycles = cycles;
117146
}
118147

119-
void ScsiController::StartSelection()
120-
{
121-
Debug("SCSI Start selection");
122-
123-
// If target ID is not 0, ignore
124-
if (m_bus.db & 0x01)
125-
{
126-
SetEvent(SCSI_EVENT_SET_COMMAND_PHASE, 75000);
127-
}
128-
}
129-
130148
void ScsiController::BusChange()
131149
{
150+
Debug("SCSI Bus change: %02X %02X", m_bus.signals, m_bus.db);
132151
switch (m_phase)
133152
{
134153
case SCSI_PHASE_COMMAND:
@@ -137,42 +156,68 @@ void ScsiController::BusChange()
137156
case SCSI_PHASE_DATA_IN:
138157
UpdateDataInPhase();
139158
break;
159+
case SCSI_PHASE_STATUS:
160+
UpdateStatusPhase();
161+
break;
162+
case SCSI_PHASE_MESSAGE_IN:
163+
UpdateMessageInPhase();
164+
break;
140165
default:
141166
break;
142167
}
143168
}
144169

170+
void ScsiController::StartSelection()
171+
{
172+
Debug("SCSI Start selection");
173+
174+
// If target ID is not 0, ignore
175+
if (m_bus.db & 0x01)
176+
{
177+
// 1ms delay
178+
SetEvent(SCSI_EVENT_SET_COMMAND_PHASE, TimeToCycles(1000));
179+
}
180+
}
181+
182+
void ScsiController::StartStatus(ScsiStatus status, u8 length)
183+
{
184+
Debug("SCSI Start status %02X", status);
185+
m_data_buffer.assign(length, (u8)status);
186+
m_bus.db = (u8)status;
187+
SetPhase(SCSI_PHASE_STATUS);
188+
}
189+
145190
void ScsiController::UpdateCommandPhase()
146191
{
147192
if (IsSignalSet(SCSI_SIGNAL_REQ) && IsSignalSet(SCSI_SIGNAL_ACK))
148193
{
149-
Debug("SCSI UpdateCommandPhase REQ and ACK set");
150194
ClearSignal(SCSI_SIGNAL_REQ);
151195
m_command_buffer.push_back(m_bus.db);
152196
}
153197
else if (!IsSignalSet(SCSI_SIGNAL_REQ) && !IsSignalSet(SCSI_SIGNAL_ACK) && m_command_buffer.size() > 0)
154198
{
155-
Debug("SCSI UpdateCommandPhase REQ and ACK not set");
156199
u8 opcode = m_command_buffer[0];
157200
u8 length = CommandLength((ScsiCommand)opcode);
158201

159202
if (length == 0)
160203
{
161204
Debug("SCSI Unknown command %02X", opcode);
162-
SetPhase(SCSI_PHASE_STATUS);
163-
m_bus.db = 0x00; // Good
205+
StartStatus(SCSI_STATUS_GOOD);
206+
m_command_buffer.clear();
164207
}
165208
else if (length <= m_command_buffer.size())
166209
{
167210
Debug("SCSI Command complete %02X", opcode);
168211
for (size_t i = 0; i < length; i++)
169212
Debug(" Command byte %02X", m_command_buffer[i]);
170213
ExecuteCommand();
214+
m_command_buffer.clear();
171215
}
172216
else
173217
{
174218
Debug("SCSI Command not complete %02X", opcode);
175-
SetEvent(SCSI_EVENT_SET_REQ_SIGNAL, 3000);
219+
// 50us delay
220+
SetEvent(SCSI_EVENT_SET_REQ_SIGNAL, TimeToCycles(50));
176221
}
177222
}
178223
}
@@ -189,21 +234,43 @@ void ScsiController::UpdateDataInPhase()
189234
}
190235
}
191236

192-
u8 ScsiController::ReadData()
237+
void ScsiController::UpdateStatusPhase()
193238
{
194-
Debug("SCSI Read data");
195-
return m_bus.db;
196-
}
197-
198-
void ScsiController::WriteData(u8 value)
199-
{
200-
Debug("SCSI Write data %02X", value);
201-
m_bus.db = value;
239+
if (IsSignalSet(SCSI_SIGNAL_REQ) && IsSignalSet(SCSI_SIGNAL_ACK))
240+
{
241+
ClearSignal(SCSI_SIGNAL_REQ);
242+
}
243+
else if (!IsSignalSet(SCSI_SIGNAL_REQ) && !IsSignalSet(SCSI_SIGNAL_ACK))
244+
{
245+
if (m_data_buffer_offset < m_data_buffer.size())
246+
{
247+
m_bus.db = m_data_buffer[m_data_buffer_offset];
248+
m_data_buffer_offset++;
249+
if (m_data_buffer_offset == m_data_buffer.size())
250+
{
251+
Debug("SCSI Status phase complete");
252+
SetPhase(SCSI_PHASE_MESSAGE_IN);
253+
}
254+
else
255+
{
256+
Debug("SCSI Status phase data %02X", m_bus.db);
257+
SetSignal(SCSI_SIGNAL_REQ);
258+
}
259+
}
260+
}
202261
}
203262

204-
u8 ScsiController::GetStatus()
263+
void ScsiController::UpdateMessageInPhase()
205264
{
206-
return (m_bus.signals & 0xF8);
265+
if (IsSignalSet(SCSI_SIGNAL_REQ) && IsSignalSet(SCSI_SIGNAL_ACK))
266+
{
267+
ClearSignal(SCSI_SIGNAL_REQ);
268+
}
269+
else if (!IsSignalSet(SCSI_SIGNAL_REQ) && !IsSignalSet(SCSI_SIGNAL_ACK))
270+
{
271+
Debug("SCSI Message in phase complete");
272+
SetPhase(SCSI_PHASE_BUS_FREE);
273+
}
207274
}
208275

209276
void ScsiController::ExecuteCommand()
@@ -244,18 +311,26 @@ void ScsiController::ExecuteCommand()
244311

245312
void ScsiController::CommandTestUnitReady()
246313
{
314+
Debug("******");
247315
Debug("SCSI CMD Test Unit Ready");
316+
Debug("******");
317+
318+
// 7ms delay
319+
SetEvent(SCSI_SET_GOOD_STATUS, TimeToCycles(7000));
248320
}
249321

250322
void ScsiController::CommandRequestSense()
251323
{
324+
Debug("******");
252325
Debug("SCSI CMD Request Sense");
326+
Debug("******");
253327
}
254328

255329
void ScsiController::CommandRead()
256330
{
331+
Debug("******");
257332
Debug("SCSI CMD Read");
258-
333+
Debug("******");
259334

260335
u32 lba = ((m_command_buffer[1] & 0x1F) << 16) | (m_command_buffer[2] << 8) | m_command_buffer[3];
261336
u16 count = m_command_buffer[4];

src/scsi_controller.h

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,20 @@ class ScsiController
7676
SCSI_EVENT_NONE,
7777
SCSI_EVENT_SET_COMMAND_PHASE,
7878
SCSI_EVENT_SET_REQ_SIGNAL,
79+
SCSI_SET_GOOD_STATUS,
80+
};
81+
82+
enum ScsiStatus
83+
{
84+
SCSI_STATUS_GOOD = 0x00,
85+
SCSI_STATUS_CHECK_CONDITION = 0x02,
86+
SCSI_STATUS_CONDITION_MET = 0x04,
87+
SCSI_STATUS_BUSY = 0x08,
88+
SCSI_STATUS_INTERMEDIATE = 0x10,
89+
SCSI_STATUS_INTERMEDIATE_CONDITION_MET = 0x14,
90+
SCSI_STATUS_RESERVATION_CONFLICT = 0x18,
91+
SCSI_STATUS_COMMAND_TERMINATED = 0x22,
92+
SCSI_STATUS_QUEUE_FULL = 0x28
7993
};
8094

8195
public:
@@ -91,31 +105,48 @@ class ScsiController
91105
void ClearSignal(u16 signals);
92106
bool IsSignalSet(ScsiSignal signal);
93107
void StartSelection();
108+
void StartStatus(ScsiStatus status, u8 length = 1);
94109
void BusChange();
95110

96111
private:
97112
void SetPhase(ScsiPhase phase);
98113
void SetEvent(ScsiEvent event, u32 cycles);
99114
void UpdateCommandPhase();
100115
void UpdateDataInPhase();
116+
void UpdateStatusPhase();
117+
void UpdateMessageInPhase();
101118
void ExecuteCommand();
102119
void CommandTestUnitReady();
103120
void CommandRequestSense();
104121
void CommandRead();
105122
u8 CommandLength(ScsiCommand command);
123+
u32 TimeToCycles(u32 us);
106124

107125
private:
108126
CdRomMedia* m_cdrom_media;
109127
ScsiBus m_bus;
110128
ScsiPhase m_phase;
111129
ScsiEvent m_next_event;
112-
u32 m_next_event_cycles;
130+
s32 m_next_event_cycles;
113131
std::vector<u8> m_command_buffer;
132+
std::vector<u8> m_data_buffer;
133+
u32 m_data_buffer_offset = 0;
114134
u32 m_read_current_lba = 0;
115135
u16 m_read_sectors_remaining = 0;
116136
u32 m_read_sector_offset = 0;
117137
};
118138

139+
static const char* k_scsi_phase_names[] = {
140+
"BUS FREE",
141+
"SELECTION",
142+
"MESSAGE OUT",
143+
"COMMAND",
144+
"DATA IN",
145+
"DATA OUT",
146+
"MESSAGE IN",
147+
"STATUS"
148+
};
149+
119150
INLINE void ScsiController::SetSignal(u16 signals)
120151
{
121152
m_bus.signals |= signals;
@@ -131,4 +162,10 @@ INLINE bool ScsiController::IsSignalSet(ScsiSignal signal)
131162
return (m_bus.signals & signal) != 0;
132163
}
133164

165+
INLINE u32 ScsiController::TimeToCycles(u32 us)
166+
{
167+
// Convert microseconds to PCE master clock cycles (21.47727 MHz) using integer math
168+
return (us * 21) + ((us * 47727) / 1000000);
169+
}
170+
134171
#endif /* SCSI_CONTROLLER_H */

0 commit comments

Comments
 (0)