2 // PC-6001/6601 disk I/O
3 // This file is based on a disk I/O program in C++
4 // by Mr. Yumitaro and translated into C for Cocoa iP6
5 // by Koichi NISHIDA 2006
9 NEC PC-6601 Emulator 'yaPC-6601'
10 NEC PC-6601SR Emulator 'yaPC-6801'
15 [ internal floppy drive ]
22 int FLOPPY::Seek88(int drvno, int trackno, int sectno)
25 if(cur_trk[drvno] != trackno) {
26 if(d_noise_seek != NULL) d_noise_seek->play();
28 cur_trk[drvno] = trackno;
29 cur_sct[drvno] = sectno;
32 if(disk[drvno]->get_track(trackno >> 1, trackno & 1)) {
33 for(int i = 0; i < disk[drvno]->sector_num.sd; i++) {
34 if(disk[drvno]->get_sector(trackno >> 1, 0/*trackno & 1*/, i)) {
35 if(disk[drvno]->id[2] == sectno) {
45 unsigned char FLOPPY::Getc88(int drvno)
47 if(drvno < 2 && disk[drvno]->sector != NULL) {
48 if(cur_pos[drvno] >= disk[drvno]->sector_size.sd) {
50 if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {
54 if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {
60 return disk[drvno]->sector[cur_pos[drvno]++];
65 int FLOPPY::Putc88(int drvno, unsigned char dat)
67 if(drvno < 2 && disk[drvno]->sector != NULL) {
68 if(cur_pos[drvno] >= disk[drvno]->sector_size.sd) {
70 if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {
74 if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {
80 disk[drvno]->sector[cur_pos[drvno]++] = dat;
86 // push data to data buffer
87 void FLOPPY::Push(int part, unsigned char data)
91 if(Index[part] < 256) Data[part][Index[part]++] = data;
94 // pop data from data buffer
95 unsigned char FLOPPY::Pop(int part)
97 if(part > 3) return 0xff;
99 if(Index[part] > 0) return Data[part][--Index[part]];
104 void FLOPPY::Clear(int i)
110 #define FDC_BUSY (0x10)
111 #define FDC_READY (0x00)
112 #define FDC_NON_DMA (0x20)
113 #define FDC_FD2PC (0x40)
114 #define FDC_PC2FD (0x00)
115 #define FDC_DATA_READY (0x80)
118 #define ST0_NOT_READY (0x08)
119 #define ST0_EQUIP_CHK (0x10)
120 #define ST0_SEEK_END (0x20)
121 #define ST0_IC_NT (0x00)
122 #define ST0_IC_AT (0x40)
123 #define ST0_IC_IC (0x80)
124 #define ST0_IC_AI (0xc0)
127 #define ST1_NOT_WRITABLE (0x02)
132 #define ST3_TRACK0 (0x10)
133 #define ST3_READY (0x20)
134 #define ST3_WRITE_PROTECT (0x40)
135 #define ST3_FAULT (0x80)
138 int FLOPPY::DiskInit66(void)
140 memset( &CmdIn, 0, sizeof( CmdBuffer ) );
141 memset( &CmdOut, 0, sizeof( CmdBuffer ) );
146 Status = FDC_DATA_READY | FDC_READY | FDC_PC2FD;
150 // push data to status buffer
151 void FLOPPY::PushStatus(int data)
153 CmdOut.Data[CmdOut.Index++] = data;
156 // pop data from status buffer
157 unsigned char FLOPPY::PopStatus()
159 return CmdOut.Data[--CmdOut.Index];
163 void FLOPPY::OutFDC(unsigned char data)
165 const int CmdLength[] = { 0,0,0,3,2,9,9,2,1,0,0,0,0,6,0,3 };
167 CmdIn.Data[CmdIn.Index++] = data;
168 if (CmdLength[CmdIn.Data[0]&0xf] == CmdIn.Index) Exec();
172 unsigned char FLOPPY::InFDC()
174 if (CmdOut.Index == 1) Status = FDC_DATA_READY | FDC_PC2FD;
184 Drv = CmdIn.Data[1]&3; // drive number No.(0-3)
185 C = CmdIn.Data[2]; // cylinder
186 H = CmdIn.Data[3]; // head address
187 R = CmdIn.Data[4]; // sector No.
188 N = CmdIn.Data[5] ? CmdIn.Data[5]*256 : 256; // sector size
190 if (disk[Drv]->inserted) {
192 // double track number(1D->2D)
193 Seek88(Drv, C*2+H, R);
194 for (i = 0; i < SendSectors; i++) {
197 Push(i, Getc88(Drv));
204 PushStatus(0); // st2
205 PushStatus(0); // st1
206 PushStatus(disk[Drv]->inserted ? 0 : ST0_NOT_READY); // st0 bit3 : media not ready
207 Status = FDC_DATA_READY | FDC_FD2PC;
211 void FLOPPY::Write(void)
216 Drv = CmdIn.Data[1]&3; // drive No.(0-3)
217 C = CmdIn.Data[2]; // cylinder
218 H = CmdIn.Data[3]; // head address
219 R = CmdIn.Data[4]; // sector No.
220 N = CmdIn.Data[5] ? CmdIn.Data[5]*256 : 256; // sector size
222 if (disk[Drv]->inserted) {
224 // double track number(1D->2D)
225 Seek88(Drv, C*2+H, R);
226 for (i=0; i<SendSectors; i++) {
227 for(j=0; j<0x100; j++)
228 Putc88(Drv, Pop(i)); // write data
236 PushStatus(0); // st2
237 PushStatus(0); // st1
239 PushStatus(disk[Drv]->inserted ? 0 : ST0_NOT_READY); // st0 bit3 : media not ready
241 Status = FDC_DATA_READY | FDC_FD2PC;
245 void FLOPPY::Seek(void)
249 Drv = CmdIn.Data[1]&3; // drive No.(0-3)
250 C = CmdIn.Data[2]; // cylinder
251 H = CmdIn.Data[3]; // head address
253 if (!disk[Drv]->inserted) { // disk unmounted ?
254 SeekST0 = ST0_IC_AT | ST0_SEEK_END | ST0_NOT_READY | Drv;
258 // double number(1D->2D)
259 Seek88(Drv, C*2+H, 1);
260 SeekST0 = ST0_IC_NT | ST0_SEEK_END | Drv;
266 // sense interrupt status
267 void FLOPPY::SenseInterruptStatus(void)
271 PushStatus(LastCylinder);
275 PushStatus(ST0_IC_IC);
278 Status = FDC_DATA_READY | FDC_FD2PC;
281 // execute FDC command
285 switch (CmdIn.Data[0] & 0xf) {
286 case 0x03: // Specify
288 case 0x05: // Write Data
291 case 0x06: // Read Data
294 case 0x08: // Sense Interrupt Status
295 SenseInterruptStatus();
297 case 0x0d: // Write ID
298 // Format is Not Implimented
300 case 0x07: // Recalibrate
301 CmdIn.Data[2] = 0; // Seek to TRACK0
305 default: ; // Invalid
310 // I/O access functions
311 void FLOPPY::OutB1H_66(unsigned char data) { DIO = data&2 ? 1 : 0; } // FD mode
312 void FLOPPY::OutB2H_66(unsigned char data) {} // FDC INT?
313 void FLOPPY::OutB3H_66(unsigned char data) {} // in out of PortB2h
314 void FLOPPY::OutD0H_66(unsigned char data) { Push(0, data); } // Buffer
315 void FLOPPY::OutD1H_66(unsigned char data) { Push(1, data); } // Buffer
316 void FLOPPY::OutD2H_66(unsigned char data) { Push(2, data); } // Buffer
317 void FLOPPY::OutD3H_66(unsigned char data) { Push(3, data); } // Buffer
318 void FLOPPY::OutD6H_66(unsigned char data) {} // select drive
319 void FLOPPY::OutD8H_66(unsigned char data) {} //
320 void FLOPPY::OutDAH_66(unsigned char data) { SendSectors = ~(data - 0x10); } // set transfer amount
321 void FLOPPY::OutDDH_66(unsigned char data) { OutFDC(data); } // FDC data register
322 void FLOPPY::OutDEH_66(unsigned char data) {} // ?
324 unsigned char FLOPPY::InB2H_66() { return 3; } // FDC INT
325 unsigned char FLOPPY::InD0H_66() { return Pop(0); } // Buffer
326 unsigned char FLOPPY::InD1H_66() { return Pop(1); } // Buffer
327 unsigned char FLOPPY::InD2H_66() { return Pop(2); } // Buffer
328 unsigned char FLOPPY::InD3H_66() { return Pop(3); } // Buffer
329 unsigned char FLOPPY::InD4H_66() { return 0; } // Mortor(on 0/off 1)
330 unsigned char FLOPPY::InDCH_66() { return Status; } // FDC status register
331 unsigned char FLOPPY::InDDH_66() { return InFDC(); } // FDC data register
333 void FLOPPY::initialize()
335 for(int i = 0; i < 2; i++) {
336 disk[i] = new DISK(emu);
337 disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
338 disk[i]->drive_type = DRIVE_TYPE_2D;
340 if(d_noise_seek != NULL) {
341 d_noise_seek->set_device_name(_T("Noise Player (FDD Seek)"));
342 if(!d_noise_seek->load_wav_file(_T("FDDSEEK.WAV"))) {
343 if(!d_noise_seek->load_wav_file(_T("FDDSEEK1.WAV"))) {
344 d_noise_seek->load_wav_file(_T("SEEK.WAV"));
347 d_noise_seek->set_mute(!config.sound_noise_fdd);
349 // if(d_noise_head_down != NULL) {
350 // d_noise_head_down->set_device_name(_T("Noise Player (FDD Head Load)"));
351 // d_noise_head_down->load_wav_file(_T("HEADDOWN.WAV"));
352 // d_noise_head_down->set_mute(!config.sound_noise_fdd);
354 // if(d_noise_head_up != NULL) {
355 // d_noise_head_up->set_device_name(_T("Noise Player (FDD Head Unload)"));
356 // d_noise_head_up->load_wav_file(_T("HEADUP.WAV"));
357 // d_noise_head_up->set_mute(!config.sound_noise_fdd);
362 void FLOPPY::release()
364 for(int i = 0; i < 2; i++) {
375 memset(Index, 0, sizeof(Index));
378 void FLOPPY::write_io8(uint32_t addr, uint32_t data)
381 uint16_t port=(addr & 0x00ff);
382 uint8_t Value=(data & 0xff);
401 d_ext->write_io8(0, data);
408 d_ext->write_io8(1, data);
415 d_ext->write_io8(2, data);
422 d_ext->write_io8(3, data);
429 d_ext->write_io8(0, data);
434 d_ext->write_io8(1, data);
439 d_ext->write_io8(2, data);
446 d_ext->write_io8(3, data);
465 uint32_t FLOPPY::read_io8(uint32_t addr)
468 uint16_t port=(addr & 0x00ff);
471 switch(addr & 0xff) {
478 Value=d_ext->read_io8(0);
485 Value=d_ext->read_io8(1);
492 Value=d_ext->read_io8(2);
499 Value=d_ext->read_io8(3);
506 Value=d_ext->read_io8(0);
513 Value=d_ext->read_io8(1);
518 Value=d_ext->read_io8(2);
523 Value=d_ext->read_io8(3);
536 uint32_t FLOPPY::read_signal(int ch)
540 for(int drv = 0; drv < 2; drv++) {
549 void FLOPPY::open_disk(int drv, const _TCHAR* file_path, int bank)
552 disk[drv]->open(file_path, bank);
557 void FLOPPY::close_disk(int drv)
559 if(drv < 2 && disk[drv]->inserted) {
564 bool FLOPPY::is_disk_inserted(int drv)
567 return disk[drv]->inserted;
572 void FLOPPY::is_disk_protected(int drv, bool value)
575 disk[drv]->write_protected = value;
579 bool FLOPPY::is_disk_protected(int drv)
582 return disk[drv]->write_protected;
587 void FLOPPY::update_config()
589 if(d_noise_seek != NULL) {
590 d_noise_seek->set_mute(!config.sound_noise_fdd);
592 // if(d_noise_head_down != NULL) {
593 // d_noise_head_down->set_mute(!config.sound_noise_fdd);
595 // if(d_noise_head_up != NULL) {
596 // d_noise_head_up->set_mute(!config.sound_noise_fdd);
600 #define STATE_VERSION 1
602 bool FLOPPY::process_state(FILEIO* state_fio, bool loading)
604 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
607 if(!state_fio->StateCheckInt32(this_device_id)) {
610 state_fio->StateUint8(io_B1H);
611 for(int i = 0; i < 2; i++) {
612 if(!disk[i]->process_state(state_fio, loading)) {
616 //state_fio->StateBuffer(cur_trk, sizeof(cur_trk), 1);
617 for(int i = 0; i < (sizeof(cur_trk) / sizeof(int)); i++) {
618 state_fio->StateInt32(cur_trk[i]);
620 //state_fio->StateBuffer(cur_sct, sizeof(cur_sct), 1);
621 for(int i = 0; i < (sizeof(cur_sct) / sizeof(int)); i++) {
622 state_fio->StateInt32(cur_sct[i]);
624 //state_fio->StateBuffer(cur_pos, sizeof(cur_pos), 1);
625 for(int i = 0; i < (sizeof(cur_pos) / sizeof(int)); i++) {
626 state_fio->StateInt32(cur_pos[i]);
628 //state_fio->StateBuffer(access, sizeof(access), 1);
629 for(int i = 0; i < (sizeof(access) / sizeof(bool)); i++) {
630 state_fio->StateBool(access[i]);
632 state_fio->StateBuffer(Data, sizeof(Data), 1);
633 //state_fio->StateBuffer(Index, sizeof(Index), 1);
634 for(int i = 0; i < (sizeof(Index) / sizeof(int)); i++) {
635 state_fio->StateInt32(Index[i]);
637 //state_fio->StateBuffer(&CmdIn, sizeof(CmdBuffer), 1);
639 state_fio->StateBuffer(CmdIn.Data, sizeof(CmdIn.Data), 1);
640 state_fio->StateInt32(CmdIn.Index);
642 //state_fio->StateBuffer(&CmdOut, sizeof(CmdBuffer), 1);
644 state_fio->StateBuffer(CmdOut.Data, sizeof(CmdOut.Data), 1);
645 state_fio->StateInt32(CmdOut.Index);
647 state_fio->StateUint8(SeekST0);
648 state_fio->StateUint8(LastCylinder);
649 state_fio->StateInt32(SeekEnd);
650 state_fio->StateUint8(SendSectors);
651 state_fio->StateInt32(DIO);
652 state_fio->StateUint8(Status);