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