Floppy-Disk-Treiber - Überarbeitung und Ausbau
-
Problem deutlich entschärft, lag im Timer. Ab Version 31 geht fdir nun mit Bochs und realer Hardware (2 von 3 bei mir).
VirtualPC macht noch Mucken. Das Problem wurde bei www.brokenthorn beschrieben, die Lösung habe ich jedoch nicht verstanden bisher. Vielleicht kann mir da jemand auf die Sprünge helfen?
-
Es gibt bei mancher Hardware ein problem beim zweiten 'fdir'. Da fängt sich der Rechner irgendwo. Durch Debuggen Fehlerort gefunden:
ich habe den Fehlerort gefunden, der einige Hardware beim zweiten fdir ausbremst:
flpydsk_send_command (cyl); putch('c'); flpydsk_wait_irq(); putch('d');
das 'd' kommt nicht
also hängt er beim zweiten mal bei der Funktion: flpydsk_wait_irq();Diese Funktion hat fricky schon als verdächtig erkannt:
{ while ( _FloppyDiskIRQ == false) // wait for irq to fire ; /// <--- freeze!!! /// _FloppyDiskIRQ = false; }
Nun brauchen wir nur noch eine Lösung, aber das findet sich.
Hier steht was: http://wiki.osdev.org/Floppy_Disk_Controller#When_waiting_for_IRQ6.2C_I_get_stuck.21
-
Revision 32 funktioniert bereits sehr gut, nur noch geringe Probleme. Nun kann man an das Thema Laden/Speichern/Löschen/Formatieren(FAT12) auf Diskette gehen. Dies hat aber nichts mehr mit dem eigentlichen Gerätetreiber zu schaffen, sondern ist ein Thema des Filesystems, hier FAT12.
EDIT: das wird nun in fat12.h/c bearbeitet.
-
Vorschlag aus dem IRC:
<XanClic>Ach, btw, ehenkes: Habt ihr mal über sowas nachgedacht? http://lowlevel.brainsware.org/forum/index.php?topic=2389.msg27064#msg27064
<ehenkes>das mit dem zurückschalten auf RM, von floppy laden/schreiben, dann zurück nach PM könnte eine Menge sparen.
<XanClic>VM8086 wäre hübscher, aber so ist es gemeint, jo
<ehenkes>ich kenne mich damit nur noch nicht aus
<Tobiking>Das klingt aber irgendwie unschön
<XanClic>Aber solange es keinen USB-Treiber gibt, ist das allemal besser
<XanClic>...Als gar kein Treiber
<Tobiking>Achso für USB wäre es natürlich eine schnelle lösung
<ehenkes>klappt das auch mit Floppy an USB?
<XanClic>Jo, klappt mit allem, was das BIOS unterstützt
<Tobiking>Klar das ist wie im Bootloader
<ehenkes>Interessante Idee
<ehenkes>aber Sektoren Lesen/Schreiben können wir ja schon
<ehenkes>allerdings nicht über USB
<XanClic>Jo, wie es im Thread steht - als Zweittreiber eben
<ehenkes>das ist quasi VM86?
<XanClic>Jo
-
Leider existiert beim Sektoren schreiben noch ein Problem mit echter Hardware:
http://www.c-plusplus.net/forum/viewtopic-var-p-is-1844268.html#1844268Vielleicht kennt sich da jemand aus und kann helfen?
Mit folgender Prozedur versuche ich das Problem auf echter Hardware (qemu mit echter Floppy funktioniert!) einzugrenzen:
int32_t flpydsk_write_sector(int32_t sectorLBA) { if (_CurrentDrive >= 4) return -1; // convert LBA sector to CHS int32_t head=0, track=0, sector=1; flpydsk_lba_to_chs(sectorLBA, &head, &track, §or); // turn motor on and seek to track printformat("before turning motor on\n"); flpydsk_control_motor(true); printformat("before seeking track\n"); if(flpydsk_seek (track, head)) return -2; printformat("before writing sector and turning motor off\n"); // write sector and turn motor off flpydsk_transfer_sector(head, track, sector, 1); flpydsk_control_motor(false); return 0; }
Ergebnis:
before turning motor on
before seeking track
error write_sector. left: 1
before turning motor on
before seeking track
error write_sector. left: 0
timeout
E_Disk ...Damit ist klar, dass das Problem hier liegt:
if(flpydsk_seek (track, head)) return -2;
Nächster Schritt: Analyse von flpydsk_seek (track, head):
// seek to given track/cylinder int32_t flpydsk_seek( uint32_t cyl, uint32_t head ) { uint32_t st0, cyl0; if (_CurrentDrive >= 4) return -1; int32_t i; for(i=0; i<10; ++i) { // send the command flpydsk_send_command (FDC_CMD_SEEK); flpydsk_send_command ( (head) << 2 | _CurrentDrive); flpydsk_send_command (cyl); printformat("i=%d ", i); flpydsk_wait_irq(); flpydsk_check_int(&st0,&cyl0); if ( cyl0 == cyl) // found the cylinder? { printformat("cylinder found\n"); printformat("cyl0: %d cyl: %d \n",cyl0,cyl); return 0; } } printformat("cylinder not found\n"); printformat("cyl0: %d cyl: %d \n",cyl0,cyl); return -1; }
Resultat:
i=0 cylinder found
cyl0: 0 cyl: 0
i=0 ... i=9 cylinder not found
cyl0: 128 cyl: 0
error write_sector ...Da stimmt etwas nicht mit dem Verlassen der for-Schleife.
Folgende Version mit richtigem 'break' führt zumindest zum Formatiervorgang auf realer Hardware:// seek to given track/cylinder // TODO: does not work perfectly with write_sector on real hardware int32_t flpydsk_seek( uint32_t cyl, uint32_t head ) { int32_t retVal; uint32_t st0, cyl0; if (_CurrentDrive >= 4) return -1; int32_t i; for(i=0; i<5; ++i) { // send the command flpydsk_send_command (FDC_CMD_SEEK); flpydsk_send_command ( (head) << 2 | _CurrentDrive); flpydsk_send_command (cyl); printformat("i=%d ", i); flpydsk_wait_irq(); flpydsk_check_int(&st0,&cyl0); if(cyl0 == cyl) // found the cylinder? { retVal = 0; break; } } if(retVal==0) { printformat("cylinder found\n"); printformat("cyl0: %d cyl: %d \n",cyl0,cyl); return 0; } else { printformat("cylinder not found\n"); printformat("cyl0: %d cyl: %d \n",cyl0,cyl); return -1; } }
Noch nicht perfekt, aber immerhin ein Einstieg! ==> Rev. 62
-
Rev. 63: Problem besteht noch:
// seek to given track/cylinder // TODO: does not work perfectly with write_sector on real hardware int32_t flpydsk_seek( uint32_t cyl, uint32_t head ) { int32_t retVal; uint32_t st0, cyl0, i; if (_CurrentDrive >= 4) { return -2; } for(i=0; i<10; ++i) { // send the command flpydsk_send_command (FDC_CMD_SEEK); flpydsk_send_command ( (head) << 2 | _CurrentDrive); flpydsk_send_command (cyl); printformat("i=%d ", i); flpydsk_wait_irq(); flpydsk_check_int(&st0,&cyl0); if(cyl0 == cyl) // found the cylinder? { retVal = 0; break; } else { retVal = -1; } } if(retVal==0) { printformat("cyl. found\t"); printformat("cyl0: %d cyl: %d \n",cyl0,cyl); return 0; } else { printformat("cyl. not found\t"); printformat("cyl0: %d cyl: %d \n",cyl0,cyl); return -1; } }
-
Nach dem Einbau eines "calibrate" (setzt auf cyl. 0) klappt der seek-Vorgang:
// seek to given track/cylinder int32_t flpydsk_seek( uint32_t cyl, uint32_t head ) { int32_t retVal; uint32_t st0, cyl0, i; if (_CurrentDrive >= 4) { return -2; } /// TEST flpydsk_calibrate(_CurrentDrive); // calibrate the disk ==> cyl. 0 flpydsk_control_motor(true); /// TEST for(i=0; i<10; ++i) { // send the command flpydsk_send_command (FDC_CMD_SEEK); flpydsk_send_command ( (head) << 2 | _CurrentDrive); flpydsk_send_command (cyl); printformat("i=%d ", i); flpydsk_wait_irq(); flpydsk_check_int(&st0,&cyl0); if(cyl0 == cyl) // found the cylinder? { retVal = 0; break; } else { retVal = -1; } } if(retVal==0) { printformat("cyl. found\t"); printformat("cyl0: %d cyl: %d \n",cyl0,cyl); return 0; } else { printformat("cyl. not found\t"); printformat("cyl0: %d cyl: %d \n",cyl0,cyl); return -1; } }
Optimierungspotential:
- Motor on/off
- Sektoren vs. Track schreiben
- Root Dir sieht merkwürdig aus bei fdir (im Windows Explorer oder nach dir a: in der Konsole kommen keine seltsamen Zeichen). Auf einem PC führt das Format zu einem für Windows unlesbaren Format, auf einem anderen ist alles ok.
- Quickformat vs. richtiges wipe out im Datenbereich?Bei qemu ist noch alles ok.
-
Motor on/off ab Rev. 66 sparsamer eingesetzt. Nun muss der Aufbau mit dem Schreiben in einzelne Sektoren ersetzt werden druch ein trackweises Schreiben, das ja bereits läuft, aber noch nicht genutzt wird.
-
Trackwises Schreiben geht inzwischen (Rev. 68), ist natürlich viel schneller.
-
Ich habe diesen Kommentar abgesetzt:
http://wiki.osdev.org/ISA_DMA#Floppy_Disk_DMA_ProgrammingNachdem wir (MrX, Cuervo, Erhard Henkes) doch signifikante Probleme mit dem Autoinit-Bit der DMA hatten, verzichten wir komplett darauf und initialisieren direkt vor der Vorbereitung auf Lesen/Schreiben:
// initialize DMA void flpydsk_initialize_dma() { outportb(0x0a, 0x06); // mask dma channel 2 outportb(0xd8, 0xFF); // reset master flip-flop outportb(0x04, 0x00); // DMA buffer address 0x1000 outportb(0x04, 0x10); outportb(0xd8, 0xFF); // reset master flip-flop outportb(0x05, 0xFF); // count to 0x23FF (number of bytes in a 3.5" floppy disk track: 18*512) outportb(0x05, 0x23); outportb(0x81, 0x00); // external page register = 0 outportb(0x0a, 0x02); // unmask dma channel 2 } /// autoinit ( 2^4 = 16 = 0x10 ) creates problems with MS Virtual PC and on real hardware! /// hence, it is not used here, but reinitialization is used before read/write // prepare the DMA for read transfer void flpydsk_dma_read() { outportb(0x0a, 0x06); // mask dma channel 2 outportb(0x0b, 0x46); // single transfer, address increment, read, channel 2 // without autoinit outportb(0x0a, 0x02); // unmask dma channel 2 } // prepare the DMA for write transfer void flpydsk_dma_write() { outportb(0x0a, 0x06); // mask dma channel 2 outportb(0x0b, 0x4A); // single transfer, address increment, write, channel 2 // without autoinit outportb(0x0a, 0x02); // unmask dma channel 2 }
int32_t flpydsk_transfer_sector(uint8_t head, uint8_t track, uint8_t sector, uint8_t operation) { uint32_t st0, cyl; flpydsk_initialize_dma(); if(operation == 0) // read a sector { flpydsk_dma_read(); flpydsk_send_command( FDC_CMD_READ_SECT | FDC_CMD_EXT_MULTITRACK | FDC_CMD_EXT_SKIP | FDC_CMD_EXT_DENSITY); } if(operation == 1) // write a sector { flpydsk_dma_write(); flpydsk_send_command( FDC_CMD_WRITE_SECT | FDC_CMD_EXT_MULTITRACK | FDC_CMD_EXT_DENSITY ); } flpydsk_send_command( head << 2 | _CurrentDrive ); flpydsk_send_command( track); flpydsk_send_command( head); flpydsk_send_command( sector); flpydsk_send_command( FLPYDSK_SECTOR_DTL_512 ); flpydsk_send_command( FLPY_SECTORS_PER_TRACK ); flpydsk_send_command( FLPYDSK_GAP3_LENGTH_3_5 ); flpydsk_send_command( 0xFF ); flpydsk_wait_irq(); int32_t j,retVal; for(j=0; j<7; ++j) { int32_t val = flpydsk_read_data(); // read status info: ST0 ST1 ST2 C H S Size(2: 512 Byte) if((j==6) && (val==2)) // value 2 means 512 Byte { retVal = 0; } else { retVal = -1; } } flpydsk_check_int(&st0,&cyl); // inform FDC that we handled interrupt return retVal; }
-
www.brokenthorn.com hatte im Kapitel 20 (Floppy Disk Treiber) noch das Autoinit-Bit gesetzt, ist nun im Kapitel 21 (DMA Treiber) offensichtlich ebenfalls auf diese deutlich zuverlässigere Technik eingeschwenkt. Dort war die Motivation die Simulation mittels MS Virtual PC.