1 // Killer Instinct hd image:
2 // Tag='GDDD' Index=0 Length=34 bytes
3 // CYLS:419,HEADS:13,SECS:47,BPS:512.
4 /*#include <string>
5 #include <fstream>
6 #include <cstdio>
7 #include <cstring>*/
8 #include "ide.h"
9
10 #define DEBUG_ATA 0
11
12 #if DEBUG_ATA
13 # define ata_log(...) printf("ata_device: " __VA_ARGS__); fflush(stdout)
14 #else
15 # define ata_log(...)
16 #endif
17
18 char* TCHARToANSI(const TCHAR* pszInString, char* pszOutString, INT32 nOutSize);
19 #define _TtoA(a) TCHARToANSI(a, NULL, 0)
20
21 namespace ide
22 {
23
24
25 using namespace std;
26
27 enum ata_registers {
28 REG_DATA = 0,
29 REG_ERROR_RO = 1,
30 REG_SECTOR_COUNT = 2,
31 REG_SECTOR_NUMBER = 3,
32 REG_CYLINDER_LOW = 4,
33 REG_CYLINDER_HIGH = 5,
34 REG_DRIVE_HEAD = 6,
35 REG_STATUS_RO = 7,
36 REG_FEATURES_WO = 1,
37 REG_COMMAND_WO = 7
38 };
39
40 enum ata_alt_registers {
41 REG_ALT_STATUS_RO = 6,
42 REG_ALT_DRIVE_ADDRESS_RO = 7,
43 REG_ALT_DEV_CONTROL_WO = 6
44 };
45
46 enum ata_commands {
47 CMD_EXEC_DRIVE_DIAG = 0x90,
48 CMD_FORMAT_TRACK = 0x50,
49 CMD_INIT_DRIVE_PARAM = 0x91,
50 CMD_READ_LONG = 0x22,
51 CMD_READ_LONG_NO_RETRY = 0x23,
52 CMD_READ_SECTOR = 0x20,
53 CMD_READ_SECTOR_NO_RETRY = 0x21,
54 CMD_VERIFY_SECTOR = 0x40,
55 CMD_VERIFY_SECTOR_NO_RETRY = 0x41,
56 CMD_RECALIBRATE = 0x10,
57 CMD_WRITE_LONG = 0x32,
58 CMD_WRITE_LONG_NO_RETRY = 0x33,
59 CMD_WRITE_SECTOR = 0x30,
60 CMD_WRITE_SECTOR_NO_RETRY = 0x31,
61 CMD_IDENTIFY_DRIVE = 0xEC
62 };
63
64 enum transfer_operations {
65 TRF_NONE = 0,
66 TRF_SECTOR_READ,
67 TRF_SECTOR_WRITE,
68 TRF_IDENTIFY
69 };
70
71 enum ata_status_flags {
72 ST_ERR = 1,
73 ST_IDX = 2,
74 ST_CORR = 4,
75 ST_DRQ = 8,
76 ST_DSC = 16,
77 ST_DF = 32,
78 ST_DRDY = 64,
79 ST_BSY = 128
80 };
81
82 enum ata_error_flags {
83 ERR_AMNF = 1,
84 ERR_TKNONF = 2,
85 ERR_ABRT = 4,
86 ERR_MCR = 8,
87 ERR_IDNF = 16,
88 ERR_MC = 32,
89 ERR_UNC = 64
90 };
91
ide_disk()92 ide_disk::ide_disk()
93 {
94 reset();
95 m_buffer_pos = 0;
96 m_buffer = new unsigned short[256];
97 m_irq_callback = NULL;
98 }
99
~ide_disk()100 ide_disk::~ide_disk()
101 {
102 delete[] m_buffer;
103
104 if (m_disk_image) {
105 fclose(m_disk_image);
106 m_disk_image = NULL;
107 }
108 }
109
set_irq_callback(void (* irq)(int))110 void ide_disk::set_irq_callback(void (*irq)(int))
111 {
112 m_irq_callback = irq;
113 }
114
reset()115 void ide_disk::reset()
116 {
117 // Killer Instinct geometry
118 // CYLS:419,HEADS:13,SECS:47,BPS:512.
119 m_num_cylinders = 419;
120 m_num_heads = 13;
121 m_num_sectors = 47;
122 m_num_bytes_per_sector = 512;
123
124 m_status = 0;
125 build_identify_buffer();
126 }
127
execute()128 void ide_disk::execute()
129 {
130 switch (m_command) {
131 case CMD_EXEC_DRIVE_DIAG: cmd_exec_drive_diag(); break;
132 case CMD_INIT_DRIVE_PARAM: cmd_init_drive_params(); break;
133 case CMD_READ_LONG: cmd_read_long(); break;
134 case CMD_READ_LONG_NO_RETRY: cmd_read_long_wor(); break;
135 case CMD_READ_SECTOR: cmd_read_sector(); break;
136 case CMD_READ_SECTOR_NO_RETRY: cmd_read_sector_wor(); break;
137 case CMD_WRITE_LONG: cmd_write_long(); break;
138 case CMD_WRITE_LONG_NO_RETRY: cmd_write_long_wor(); break;
139 case CMD_WRITE_SECTOR: cmd_write_sector(); break;
140 case CMD_WRITE_SECTOR_NO_RETRY: cmd_write_sector_wor(); break;
141 case CMD_IDENTIFY_DRIVE: cmd_indentify_drive(); break;
142 default:
143 ata_log("unimplemented command %x\n", m_command);
144 break;
145 }
146 }
147
build_identify_buffer()148 void ide_disk::build_identify_buffer()
149 {
150 memset(m_identify_buffer, 0, sizeof(m_identify_buffer));
151
152 // Killer Instinct 1
153 m_identify_buffer[0] = 0x5354;
154 m_identify_buffer[1] = 0x3931;
155 m_identify_buffer[2] = 0x3530;
156 m_identify_buffer[3] = 0x4147;
157 m_identify_buffer[4] = 0x2020;
158 m_identify_buffer[6] = m_num_sectors;
159
160 // serial number
161 for (int i = 0; i < 10; i++)
162 m_identify_buffer[10 + i] = '0';
163
164 strncpy((char *) &m_identify_buffer[27], "Generic IDE HD", 27);
165
166
167 // KI I
168 m_identify_buffer[10] = ('0' << 8) | '0';
169 m_identify_buffer[11] = ('S' << 8) | 'T';
170 m_identify_buffer[12] = ('9' << 8) | '1';
171 m_identify_buffer[13] = ('5' << 8) | '0';
172 m_identify_buffer[14] = ('A' << 8) | 'G';
173
174 // KI II
175 m_identify_buffer[27] = ('S' << 8) | 'T';
176 m_identify_buffer[28] = ('9' << 8) | '1';
177 m_identify_buffer[29] = ('5' << 8) | '0';
178 m_identify_buffer[30] = ('A' << 8) | 'G';
179 m_identify_buffer[31] = (' ' << 8) | ' ';
180 }
181
chs_to_lba(int cylinder,int head,int sector)182 unsigned ide_disk::chs_to_lba(int cylinder, int head, int sector)
183 {
184 return ((cylinder * m_num_heads + head) * m_num_sectors) + sector - 1;
185 }
186
chs_next_sector()187 void ide_disk::chs_next_sector()
188 {
189 m_sector_number++;
190 if (m_sector_number >= m_num_sectors) {
191 m_sector_number = 0;
192 m_drive_head++;
193 if (m_drive_head >= m_num_heads) {
194 m_drive_head = 0;
195 m_cylinder_low++;
196 if (m_cylinder_low >= 256) {
197 m_cylinder_low = 0;
198 m_cylinder_high++;
199 }
200 }
201 }
202 }
203
lba_from_regs()204 unsigned ide_disk::lba_from_regs()
205 {
206 return chs_to_lba(m_cylinder_low | (m_cylinder_high << 8), m_drive_head, m_sector_number);
207 }
208
is_drive_ready()209 inline bool ide_disk::is_drive_ready()
210 {
211 if (m_status & ST_DRDY)
212 return true;
213
214 m_error |= ERR_ABRT;
215 m_status |= ST_ERR;
216 m_status &= ~ST_BSY;
217 }
218
raise_interrupt()219 void ide_disk::raise_interrupt()
220 {
221 if (~m_device_control & 2)
222 if (m_irq_callback)
223 m_irq_callback(1);
224 }
225
clear_interrupt()226 void ide_disk::clear_interrupt()
227 {
228 if (m_irq_callback)
229 m_irq_callback(0);
230 }
231
232
write(unsigned offset,unsigned value)233 void ide_disk::write(unsigned offset, unsigned value)
234 {
235 //ata_log("[%x] write: %x = %x\n", mips::g_mips->m_state.pc, offset, value);
236
237 switch (offset) {
238 case REG_COMMAND_WO:
239
240 m_command = value;
241 execute();
242
243 break;
244
245 case REG_DATA:
246 if (m_status & ST_DRQ) {
247 if (m_transfer_operation == TRF_SECTOR_WRITE) {
248 m_buffer[m_buffer_pos++] = value;
249 //ata_log("ata_write_data: %02x\n", value);
250 if (m_buffer_pos >= m_num_bytes_per_sector / 2)
251 update_transfer();
252 }
253 }
254 break;
255
256 case REG_FEATURES_WO:
257 break;
258
259 case REG_SECTOR_COUNT:
260 m_sector_count = value;
261 break;
262
263 case REG_SECTOR_NUMBER:
264 m_sector_number = value;
265 break;
266
267 case REG_CYLINDER_LOW:
268 m_cylinder_low = value;
269 break;
270
271 case REG_CYLINDER_HIGH:
272 m_cylinder_high = value;
273 break;
274
275 case REG_DRIVE_HEAD:
276 m_drive_head = value;
277 break;
278 }
279 }
280
write_alternate(unsigned offset,unsigned value)281 void ide_disk::write_alternate(unsigned offset, unsigned value)
282 {
283 ata_log("write_alt: %x = %x\n", offset, value);
284 m_device_control = value;
285 }
286
read(unsigned offset)287 unsigned ide_disk::read(unsigned offset)
288 {
289 //ata_log("ata_read: %x\n", offset);
290
291 switch (offset) {
292 case REG_STATUS_RO:
293 //ata_log("ata_read_status: %x\n", offset);
294 clear_interrupt();
295 return m_status;
296
297 case REG_ERROR_RO:
298 return m_error;
299
300 case REG_DATA:
301 if (m_status & ST_DRQ) {
302 if ((m_transfer_operation == TRF_SECTOR_READ) ||
303 (m_transfer_operation == TRF_IDENTIFY)) {
304 unsigned data = m_buffer[m_buffer_pos++];
305
306 if (m_transfer_operation == TRF_IDENTIFY) {
307 ata_log("ata_read_data: %02x\n", data);
308 }
309 if (m_buffer_pos >= m_num_bytes_per_sector / 2)
310 update_transfer();
311 return data;
312 }
313 }
314 return 0;
315 case REG_SECTOR_COUNT:
316 return m_sector_count;
317 case REG_SECTOR_NUMBER:
318 return m_sector_number;
319 case REG_CYLINDER_LOW:
320 return m_cylinder_low;
321 case REG_CYLINDER_HIGH:
322 return m_cylinder_high;
323 case REG_DRIVE_HEAD:
324 return m_drive_head;
325 }
326
327 // shouldn't happen
328 return 0;
329 }
330
read_alternate(unsigned offset)331 unsigned ide_disk::read_alternate(unsigned offset)
332 {
333 //ata_log("read_alt: %x\n", offset);
334 switch (offset) {
335 case REG_ALT_DRIVE_ADDRESS_RO:
336 case REG_ALT_STATUS_RO:
337 return m_status | 0x40 /* hack? */;
338 }
339 return 0;
340 }
341
load_disk_image(const char * filename)342 bool ide_disk::load_disk_image(const char *filename)
343 {
344 char szFilePath[MAX_PATH];
345
346 sprintf(szFilePath, "%s%s", _TtoA(szAppHDDPath), filename);
347
348 m_disk_image = fopen(szFilePath, "r+b");
349 if (!m_disk_image) {
350 ata_log("disk image not found!\n");
351 return false;
352 }
353
354 return true;
355 }
356
load_hdd_image(int idx)357 int ide_disk::load_hdd_image(int idx)
358 {
359 // get setname (use parent if applicable)
360 char setname[128];
361
362 if (BurnDrvGetTextA(DRV_PARENT)) {
363 strcpy(setname, BurnDrvGetTextA(DRV_PARENT));
364 } else {
365 strcpy(setname, BurnDrvGetTextA(DRV_NAME));
366 }
367
368 // get hdd name
369 char *szHDDNameTmp = NULL;
370 BurnDrvGetHDDName(&szHDDNameTmp, idx, 0);
371
372 // make the path
373 char path[256];
374 sprintf(path, "%s/%s", setname, szHDDNameTmp);
375
376 // null terminate
377 path[strlen(path)] = '\0';
378
379 if (!load_disk_image(path)) {
380 return 1;
381 }
382
383 return 0;
384 }
385
setup_transfer(int mode)386 void ide_disk::setup_transfer(int mode)
387 {
388 m_transfer_operation = mode;
389
390 m_buffer_pos = 0;
391 if (m_sector_count == 0)
392 m_sector_count = 256;
393
394 if (mode == TRF_IDENTIFY)
395 m_sector_count = 1;
396
397 m_transfer_write_first = true;
398 update_transfer();
399 m_transfer_write_first = false;
400 }
401
update_transfer()402 void ide_disk::update_transfer()
403 {
404 if (m_transfer_operation == TRF_NONE)
405 return;
406
407 if (m_sector_count < 0) {
408 m_status &= ~ST_DRQ;
409 m_transfer_operation = TRF_NONE;
410 return;
411 }
412
413 unsigned lba = 0;
414 switch (m_transfer_operation) {
415 case TRF_IDENTIFY:
416 memcpy(m_buffer, m_identify_buffer, sizeof(m_identify_buffer));
417 break;
418
419 case TRF_SECTOR_WRITE:
420 if (!m_transfer_write_first)
421 flush_write_transfer();
422
423 case TRF_SECTOR_READ:
424 lba = lba_from_regs() * m_num_bytes_per_sector;
425 m_last_buffer_lba = lba;
426
427 fseek(m_disk_image, lba, SEEK_SET);
428 fread(m_buffer, m_num_bytes_per_sector, 1, m_disk_image);
429 m_buffer_pos = 0;
430
431 chs_next_sector();
432 break;
433 }
434
435
436 m_sector_count--;
437 m_status |= ST_DRQ;
438 raise_interrupt();
439 }
440
flush_write_transfer()441 void ide_disk::flush_write_transfer()
442 {
443 ata_log("flush write buffer\n");
444
445 fseek(m_disk_image, m_last_buffer_lba, SEEK_SET);
446 fwrite(m_buffer, m_num_bytes_per_sector, 1, m_disk_image);
447 }
448
449 // ========================================================================== //
450 // ATA COMMANDS //
451 // ========================================================================== //
452
cmd_exec_drive_diag()453 void ide_disk::cmd_exec_drive_diag()
454 {
455 ata_log("exec_drive_dialog()\n");
456 }
457
cmd_init_drive_params()458 void ide_disk::cmd_init_drive_params()
459 {
460 ata_log("init_drive_params(logsec_per_logtrack=%d, logheads=%d)\n",
461 m_sector_count, m_drive_head - 1);
462
463 m_num_sectors = m_sector_count;
464 m_num_heads = (m_drive_head & 0xF) + 1;
465
466 m_status |= ST_DRDY;
467 m_status &= ~ST_BSY;
468 raise_interrupt();
469 }
470
cmd_read_long()471 void ide_disk::cmd_read_long()
472 {
473 ata_log("read_long(cyl_lo=%d, cyl_hi=%d, head=%d, sector=%d) [sec_count=%d]\n",
474 m_cylinder_low, m_cylinder_high, m_drive_head,
475 m_sector_number, m_sector_count);
476 }
477
cmd_read_long_wor()478 void ide_disk::cmd_read_long_wor()
479 {
480 ata_log("read_long_wor(cyl_lo=%d, cyl_hi=%d, head=%d, sector=%d) [sec_count=%d]\n",
481 m_cylinder_low, m_cylinder_high, m_drive_head,
482 m_sector_number, m_sector_count);
483 }
484
cmd_read_sector()485 void ide_disk::cmd_read_sector()
486 {
487 ata_log("read_sector(cyl_lo=%d, cyl_hi=%d, head=%d, sector=%d, sec_count=%d) [%0x]\n",
488 m_cylinder_low, m_cylinder_high, m_drive_head,
489 m_sector_number, m_sector_count,
490 chs_to_lba(m_cylinder_low | (m_cylinder_high << 8), m_drive_head, m_sector_number));
491
492 setup_transfer(TRF_SECTOR_READ);
493 }
494
cmd_read_sector_wor()495 void ide_disk::cmd_read_sector_wor()
496 {
497 ata_log("read_sector_wor(cyl_lo=%d, cyl_hi=%d, head=%d, sector=%d, sec_count=%d) [%0x]\n",
498 m_cylinder_low, m_cylinder_high, m_drive_head,
499 m_sector_number, m_sector_count,
500 chs_to_lba(m_cylinder_low | (m_cylinder_high << 8), m_drive_head, m_sector_number));
501 }
502
cmd_write_long()503 void ide_disk::cmd_write_long()
504 {
505 ata_log("write_long(cyl_lo=%d, cyl_hi=%d, head=%d, sector=%d) [sec_count=%d]\n",
506 m_cylinder_low, m_cylinder_high, m_drive_head,
507 m_sector_number, m_sector_count);
508 }
509
cmd_write_long_wor()510 void ide_disk::cmd_write_long_wor()
511 {
512 ata_log("write_long_wor(cyl_lo=%d, cyl_hi=%d, head=%d, sector=%d) [sec_count=%d]\n",
513 m_cylinder_low, m_cylinder_high, m_drive_head,
514 m_sector_number, m_sector_count);
515 }
516
cmd_write_sector()517 void ide_disk::cmd_write_sector()
518 {
519 ata_log("write_sector(cyl_lo=%d, cyl_hi=%d, head=%d, sector=%d, sec_count=%d) [%0x]\n",
520 m_cylinder_low, m_cylinder_high, m_drive_head,
521 m_sector_number, m_sector_count,
522 chs_to_lba(m_cylinder_low | (m_cylinder_high << 8), m_drive_head, m_sector_number));
523
524 setup_transfer(TRF_SECTOR_WRITE);
525 }
526
cmd_write_sector_wor()527 void ide_disk::cmd_write_sector_wor()
528 {
529 ata_log("write_sector_wor(cyl_lo=%d, cyl_hi=%d, head=%d, sector=%d, sec_count=%d) [%0x]\n",
530 m_cylinder_low, m_cylinder_high, m_drive_head,
531 m_sector_number, m_sector_count,
532 chs_to_lba(m_cylinder_low | (m_cylinder_high << 8), m_drive_head, m_sector_number));
533 }
534
cmd_indentify_drive()535 void ide_disk::cmd_indentify_drive()
536 {
537 ata_log("identify_drive()\n");
538 setup_transfer(TRF_IDENTIFY);
539 }
540
541
542
543 }
544