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 ]
24 int FLOPPY::Seek88(int drvno, int trackno, int sectno)
27 if(cur_trk[drvno] != trackno) {
28 if(d_noise_seek != NULL) d_noise_seek->play();
30 cur_trk[drvno] = trackno;
31 cur_sct[drvno] = sectno;
34 if(disk[drvno]->get_track(trackno >> 1, trackno & 1)) {
35 for(int i = 0; i < disk[drvno]->sector_num.sd; i++) {
36 if(disk[drvno]->get_sector(trackno >> 1, 0/*trackno & 1*/, i)) {
37 if(disk[drvno]->id[2] == sectno) {
47 unsigned char FLOPPY::Getc88(int drvno)
49 if(drvno < 2 && disk[drvno]->sector != NULL) {
50 if(cur_pos[drvno] >= disk[drvno]->sector_size.sd) {
52 if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {
56 if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {
62 return disk[drvno]->sector[cur_pos[drvno]++];
67 int FLOPPY::Putc88(int drvno, unsigned char dat)
69 if(drvno < 2 && disk[drvno]->sector != NULL) {
70 if(cur_pos[drvno] >= disk[drvno]->sector_size.sd) {
72 if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {
76 if(!Seek88(drvno, cur_trk[drvno], cur_sct[drvno])) {
82 disk[drvno]->sector[cur_pos[drvno]++] = dat;
88 // push data to data buffer
89 void FLOPPY::Push(int part, unsigned char data)
93 if(Index[part] < 256) Data[part][Index[part]++] = data;
96 // pop data from data buffer
97 unsigned char FLOPPY::Pop(int part)
99 if(part > 3) return 0xff;
101 if(Index[part] > 0) return Data[part][--Index[part]];
106 void FLOPPY::Clear(int i)
112 #define FDC_BUSY (0x10)
113 #define FDC_READY (0x00)
114 #define FDC_NON_DMA (0x20)
115 #define FDC_FD2PC (0x40)
116 #define FDC_PC2FD (0x00)
117 #define FDC_DATA_READY (0x80)
120 #define ST0_NOT_READY (0x08)
121 #define ST0_EQUIP_CHK (0x10)
122 #define ST0_SEEK_END (0x20)
123 #define ST0_IC_NT (0x00)
124 #define ST0_IC_AT (0x40)
125 #define ST0_IC_IC (0x80)
126 #define ST0_IC_AI (0xc0)
129 #define ST1_NOT_WRITABLE (0x02)
134 #define ST3_TRACK0 (0x10)
135 #define ST3_READY (0x20)
136 #define ST3_WRITE_PROTECT (0x40)
137 #define ST3_FAULT (0x80)
140 int FLOPPY::DiskInit66(void)
142 memset( &CmdIn, 0, sizeof( CmdBuffer ) );
143 memset( &CmdOut, 0, sizeof( CmdBuffer ) );
148 Status = FDC_DATA_READY | FDC_READY | FDC_PC2FD;
152 // push data to status buffer
153 void FLOPPY::PushStatus(int data)
155 CmdOut.Data[CmdOut.Index++] = data;
158 // pop data from status buffer
159 unsigned char FLOPPY::PopStatus()
161 return CmdOut.Data[--CmdOut.Index];
165 void FLOPPY::OutFDC(unsigned char data)
167 const int CmdLength[] = { 0,0,0,3,2,9,9,2,1,0,0,0,0,6,0,3 };
169 CmdIn.Data[CmdIn.Index++] = data;
170 if (CmdLength[CmdIn.Data[0]&0xf] == CmdIn.Index) Exec();
174 unsigned char FLOPPY::InFDC()
176 if (CmdOut.Index == 1) Status = FDC_DATA_READY | FDC_PC2FD;
186 Drv = CmdIn.Data[1]&3; // drive number No.(0-3)
187 C = CmdIn.Data[2]; // cylinder
188 H = CmdIn.Data[3]; // head address
189 R = CmdIn.Data[4]; // sector No.
190 N = CmdIn.Data[5] ? CmdIn.Data[5]*256 : 256; // sector size
192 if (disk[Drv]->inserted) {
194 // double track number(1D->2D)
195 Seek88(Drv, C*2+H, R);
196 for (i = 0; i < SendSectors; i++) {
199 Push(i, Getc88(Drv));
206 PushStatus(0); // st2
207 PushStatus(0); // st1
208 PushStatus(disk[Drv]->inserted ? 0 : ST0_NOT_READY); // st0 bit3 : media not ready
209 Status = FDC_DATA_READY | FDC_FD2PC;
213 void FLOPPY::Write(void)
218 Drv = CmdIn.Data[1]&3; // drive No.(0-3)
219 C = CmdIn.Data[2]; // cylinder
220 H = CmdIn.Data[3]; // head address
221 R = CmdIn.Data[4]; // sector No.
222 N = CmdIn.Data[5] ? CmdIn.Data[5]*256 : 256; // sector size
224 if (disk[Drv]->inserted) {
226 // double track number(1D->2D)
227 Seek88(Drv, C*2+H, R);
228 for (i=0; i<SendSectors; i++) {
229 for(j=0; j<0x100; j++)
230 Putc88(Drv, Pop(i)); // write data
238 PushStatus(0); // st2
239 PushStatus(0); // st1
241 PushStatus(disk[Drv]->inserted ? 0 : ST0_NOT_READY); // st0 bit3 : media not ready
243 Status = FDC_DATA_READY | FDC_FD2PC;
247 void FLOPPY::Seek(void)
251 Drv = CmdIn.Data[1]&3; // drive No.(0-3)
252 C = CmdIn.Data[2]; // cylinder
253 H = CmdIn.Data[3]; // head address
255 if (!disk[Drv]->inserted) { // disk unmounted ?
256 SeekST0 = ST0_IC_AT | ST0_SEEK_END | ST0_NOT_READY | Drv;
260 // double number(1D->2D)
261 Seek88(Drv, C*2+H, 1);
262 SeekST0 = ST0_IC_NT | ST0_SEEK_END | Drv;
268 // sense interrupt status
269 void FLOPPY::SenseInterruptStatus(void)
273 PushStatus(LastCylinder);
277 PushStatus(ST0_IC_IC);
280 Status = FDC_DATA_READY | FDC_FD2PC;
283 // execute FDC command
287 switch (CmdIn.Data[0] & 0xf) {
288 case 0x03: // Specify
290 case 0x05: // Write Data
293 case 0x06: // Read Data
296 case 0x08: // Sense Interrupt Status
297 SenseInterruptStatus();
299 case 0x0d: // Write ID
300 // Format is Not Implimented
302 case 0x07: // Recalibrate
303 CmdIn.Data[2] = 0; // Seek to TRACK0
307 default: ; // Invalid
312 // I/O access functions
313 void FLOPPY::OutB1H_66(unsigned char data) { DIO = data&2 ? 1 : 0; } // FD mode
314 void FLOPPY::OutB2H_66(unsigned char data) {} // FDC INT?
315 void FLOPPY::OutB3H_66(unsigned char data) {} // in out of PortB2h
316 void FLOPPY::OutD0H_66(unsigned char data) { Push(0, data); } // Buffer
317 void FLOPPY::OutD1H_66(unsigned char data) { Push(1, data); } // Buffer
318 void FLOPPY::OutD2H_66(unsigned char data) { Push(2, data); } // Buffer
319 void FLOPPY::OutD3H_66(unsigned char data) { Push(3, data); } // Buffer
320 void FLOPPY::OutD6H_66(unsigned char data) {} // select drive
321 void FLOPPY::OutD8H_66(unsigned char data) {} //
322 void FLOPPY::OutDAH_66(unsigned char data) { SendSectors = ~(data - 0x10); } // set transfer amount
323 void FLOPPY::OutDDH_66(unsigned char data) { OutFDC(data); } // FDC data register
324 void FLOPPY::OutDEH_66(unsigned char data) {} // ?
326 unsigned char FLOPPY::InB2H_66() { return 3; } // FDC INT
327 unsigned char FLOPPY::InD0H_66() { return Pop(0); } // Buffer
328 unsigned char FLOPPY::InD1H_66() { return Pop(1); } // Buffer
329 unsigned char FLOPPY::InD2H_66() { return Pop(2); } // Buffer
330 unsigned char FLOPPY::InD3H_66() { return Pop(3); } // Buffer
331 unsigned char FLOPPY::InD4H_66() { return 0; } // Mortor(on 0/off 1)
332 unsigned char FLOPPY::InDCH_66() { return Status; } // FDC status register
333 unsigned char FLOPPY::InDDH_66() { return InFDC(); } // FDC data register
335 void FLOPPY::initialize()
337 for(int i = 0; i < 2; i++) {
338 disk[i] = new DISK(emu);
339 disk[i]->set_device_name(_T("%s/Disk #%d"), this_device_name, i + 1);
340 disk[i]->drive_type = DRIVE_TYPE_2D;
342 if(d_noise_seek != NULL) {
343 d_noise_seek->set_device_name(_T("Noise Player (FDD Seek)"));
344 if(!d_noise_seek->load_wav_file(_T("FDDSEEK.WAV"))) {
345 if(!d_noise_seek->load_wav_file(_T("FDDSEEK1.WAV"))) {
346 d_noise_seek->load_wav_file(_T("SEEK.WAV"));
349 d_noise_seek->set_mute(!config.sound_noise_fdd);
351 // if(d_noise_head_down != NULL) {
352 // d_noise_head_down->set_device_name(_T("Noise Player (FDD Head Load)"));
353 // d_noise_head_down->load_wav_file(_T("HEADDOWN.WAV"));
354 // d_noise_head_down->set_mute(!config.sound_noise_fdd);
356 // if(d_noise_head_up != NULL) {
357 // d_noise_head_up->set_device_name(_T("Noise Player (FDD Head Unload)"));
358 // d_noise_head_up->load_wav_file(_T("HEADUP.WAV"));
359 // d_noise_head_up->set_mute(!config.sound_noise_fdd);
364 void FLOPPY::release()
366 for(int i = 0; i < 2; i++) {
377 memset(Index, 0, sizeof(Index));
380 void FLOPPY::write_io8(uint32_t addr, uint32_t data)
383 uint16_t port=(addr & 0x00ff);
384 uint8_t Value=(data & 0xff);
403 d_ext->write_io8(0, data);
410 d_ext->write_io8(1, data);
417 d_ext->write_io8(2, data);
424 d_ext->write_io8(3, data);
431 d_ext->write_io8(0, data);
436 d_ext->write_io8(1, data);
441 d_ext->write_io8(2, data);
448 d_ext->write_io8(3, data);
467 uint32_t FLOPPY::read_io8(uint32_t addr)
470 uint16_t port=(addr & 0x00ff);
473 switch(addr & 0xff) {
480 Value=d_ext->read_io8(0);
487 Value=d_ext->read_io8(1);
494 Value=d_ext->read_io8(2);
501 Value=d_ext->read_io8(3);
508 Value=d_ext->read_io8(0);
515 Value=d_ext->read_io8(1);
520 Value=d_ext->read_io8(2);
525 Value=d_ext->read_io8(3);
538 uint32_t FLOPPY::read_signal(int ch)
542 for(int drv = 0; drv < 2; drv++) {
551 void FLOPPY::open_disk(int drv, const _TCHAR* file_path, int bank)
554 disk[drv]->open(file_path, bank);
559 void FLOPPY::close_disk(int drv)
561 if(drv < 2 && disk[drv]->inserted) {
566 bool FLOPPY::is_disk_inserted(int drv)
569 return disk[drv]->inserted;
574 void FLOPPY::is_disk_protected(int drv, bool value)
577 disk[drv]->write_protected = value;
581 bool FLOPPY::is_disk_protected(int drv)
584 return disk[drv]->write_protected;
589 void FLOPPY::update_config()
591 if(d_noise_seek != NULL) {
592 d_noise_seek->set_mute(!config.sound_noise_fdd);
594 // if(d_noise_head_down != NULL) {
595 // d_noise_head_down->set_mute(!config.sound_noise_fdd);
597 // if(d_noise_head_up != NULL) {
598 // d_noise_head_up->set_mute(!config.sound_noise_fdd);
602 #define STATE_VERSION 2
604 bool FLOPPY::process_state(FILEIO* state_fio, bool loading)
606 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
609 if(!state_fio->StateCheckInt32(this_device_id)) {
612 state_fio->StateValue(io_B1H);
613 for(int i = 0; i < 2; i++) {
614 if(!disk[i]->process_state(state_fio, loading)) {
618 state_fio->StateArray(cur_trk, sizeof(cur_trk), 1);
619 state_fio->StateArray(cur_sct, sizeof(cur_sct), 1);
620 state_fio->StateArray(cur_pos, sizeof(cur_pos), 1);
621 state_fio->StateArray(access, sizeof(access), 1);
622 state_fio->StateArray(&Data[0][0], sizeof(Data), 1);
623 state_fio->StateArray(Index, sizeof(Index), 1);
624 state_fio->StateArray(CmdIn.Data, sizeof(CmdIn.Data), 1);
625 state_fio->StateValue(CmdIn.Index);
626 state_fio->StateArray(CmdOut.Data, sizeof(CmdOut.Data), 1);
627 state_fio->StateValue(CmdOut.Index);
628 state_fio->StateValue(SeekST0);
629 state_fio->StateValue(LastCylinder);
630 state_fio->StateValue(SeekEnd);
631 state_fio->StateValue(SendSectors);
632 state_fio->StateValue(DIO);
633 state_fio->StateValue(Status);