Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: bitmaster am 11. December 2005, 12:54
-
Hi,
also ich habe mein OS jetzt im PM mit Multitasking laufen. Jetzt möchte ich einen Diskettentreiber schreiben. Also z.B. um Sektore zu lesen, zu schreiben. Das habe ich im RM mit dem int 13h gemacht. Wie mache ich das im PM? Welche Ports benötige ich. Kennt ihr ein gutes Tutorial oder so dazu?
Danke!!!
-
Hi!
Das Ding heißt Intel 82078 Floppy Controller. Ich hab mal angefangen einen Treiber für zu schreiben.
; Driver for Intel 82078 Floppy Controller
; (C)Copyright 2004 by NucleusKL Team & Authors
; Authors: Christian Lins
; Published under GPL - General Public License
; Last change: 17.02.2004
;; Primary
Port0SRB db 3F1h ; R/W Status Register B
Port0DOR db 3F2h ; R/W Digital Output Register
Port0TDR db 3F3h ; R/W Tape Drive Register
Port0MSR db 3F4h ; R Main Status Register
Port0DSR db 3F4h ; W Data Rate Select Register
Port0FIFO db 3F5h ; R/W Data (FIFO)
Port0DIR db 3F7h ; R Digital Input Register
Port0CCR db 3F7h ; W Configuration Control Register
;; Secondary
Port1SRB db 371h ; R/W Status Register B
Port1DOR db 372h ; R/W Digital Output Register
Port1TDR db 373h ; R/W Tape Drive Register
Port1MSR db 374h ; R Main Status Register
Port1DSR db 374h ; W Data Rate Select Register
Port1FIFO db 375h ; R/W Data (FIFO)
Port1DIR db 377h ; R Digital Input Register
Port1CCR db 377h ; W Configuration Control Register
ActiveDrive dw 0000h ; Nummer des aktiven Laufwerks
;; Initialisiert den FC82078
_fc82078_init:
; Paramter ActiveDrive 0, 1, 2, 3
pop ax ;ActiveDrive
call _fc82078_read_msr
; Bit 2 im DOR für Reset setzen
mov dx, Port0DOR
mov al, 00000100b
out dx, al
call _fc82078_read_msr
ret
;; Aktiviert den Motor des aktiven Laufwerks
_fc82078_motor_on:
mov dx, Port0DOR
mov al, 00010000b
out dx, al ; TODO: Drive 0 gewählt, ActiveDrive sollte gewählt werden
call _fc82078_read_msr
push 0
ret
;; Deaktiviert den Motor des aktiven Laufwerks
_fc82078_motor_off:
mov dx, Port0DOR
mov al, 0x0
out dx, al ; TODO: Drive 0 gewählt, ActiveDrive sollte gewählt werden
call _fc82078_read_msr
push 0
ret
;; Wählt die Übertragungsgeschwindigkeit
_fc82078_datarate:
push ax
mov dx, Port0DSR
mov al, 00000010b
out dx, al ; TODO: 250 kbps gewählt, andere Geschwindigkeiten sollten möglich sein
push 0
ret
;; Liest das Status Register und speichert es in al
_fc82078_read_msr:
xor al, al
mov dx, Port0MSR
in al, dx
;mov MSR, al
ret
;; Liest 16 Bytes aus dem FIFO (ohne DMA)
_fc82078_read_fifo:
mov dx, Port0FIFO
__readfifo_loop:
in al, dx ; Liest ein Byte
mov ah, al
in al, dx ; Liest noch ein Byte
push ax ; Speichert das Word auf dem Stack
call _fc82078_read_msr
cmp al, 80h ; Vergleicht ob das Lesen nun zu Ende ist
jne __readfifo_loop
push 0
ret
;; Schreibt 16 Bytes in das FIFO Register (ohne DMA)
_fc82078_write_fifo:
mov dx, Port0FIFO
__writefifo_loop:
pop ax
xchg al, ah
out dx, al
xchg al, ah
out dx, al
call _fc82078_read_msr
cmp al, 80h
jne __writefifo_loop
push 0
ret
;; Schreibt einen Befehl
Zumindest das Anschalten und Ausschalten sollte funktionieren. Vielleicht hilft dir das.
C#ris
-
Hallo, ich hab mal ein Modul in ASM geschrieben, mit dem man auch lesen und schreiben auf Disketten kann (funktionierte auch). Ist zwar etwas lang, aber ich wollt es dir nicht per Mail schicken, falls eventuell noch jemand Anderes Interesse daran hat...
Also, hier der Code (sind eigentlich 2 Dateien), interessant dürften die Funktionen FDD_WRITE_BLOCK und FDD_READ_BLOCK bzw stdfdc_read_block und stdfdc_write_block sein:
;***************************************************************************
;*** FDD ***
;***************************************************************************
; Enthâlt Funktionen f?r den Zugriff auf das Floppylaufwerk.
; Maximale Lânge einer Path-Angabe (inclusive 0):
#define MAX_PATH_LEN 100
; Struktur mit allen Daten ?ber das FDD:
#struct_start FDD_DATA_STRUCT
installed db 0 ; Merker, ob ein FDD installiert ist.
user dw 0 ; TSS des aktuellen Nutzers (0 wenn keiner).
floppy_sectors_per_fat dw 0 ; Anzahl der Sektoren pro FAT.
floppy_root_entrys dw 0 ; Maximale Anzahl an Eintrâgen im Root.
floppy_root_startblock dw 0 ; Startblock des Root.
floppy_fat_startblock dw 0 ; Startblock der 1. FAT.
buffer_blocks dw #dup(0,8) ; Nummern der Blocks in den einzelnen Buffern (bei -1 unbenutzt).
next_buffer dw 0 ; Nummer des nâchsten Bufferers zum ?berschreiben.
#struct_end
FDD_DATA_STRUCT fdd_data
;----------------------------------------------------------------------------
; FDD_INIT
;----------------------------------------------------------------------------
; Initialisiert das Floppylaufwerk.
; (cl<- = 0 - Fehler, 1 - OK)
@fdd_init(){
; Pr?fen, ob ?berhaupt ein FDD installiert ist:
cmp byte ptr [hw_fdc],0
jz .not_installed
cmp byte ptr [hw_floppys],0
jz .not_installed
mov byte ptr [fdd_data_installed],1
; Den FDC zur?cksetzen (auch ohne eingelegte Disk):
push bx
call fdc_reset
pop bx
; Alle Daten ?ber die Floppy zur?cksetzen (auch ohne eingelegte Disk):
call fdd_init_floppy_disk_changed
; Alle Buffer lâschen:
push cx
push edi
mov cx,8
mov edi,fdd_data_buffer_blocks
.reset_buffer_loop:
mov word ptr [edi],-1
add edi,2
loop .reset_buffer_loop
pop edi
mov cx,[stdfdc_dma_buffer_base]
mov [stdfdc_dma_buffer],cx
mov word ptr [fdd_data_next_buffer],0
pop cx
mov cl,1
ret
.not_installed:
mov byte ptr [fdd_data_installed],0
@add_error(dword num ERROR_FDD_NOT_INSATLLED)
.error:
mov cl,0
ret
}
;----------------------------------------------------------------------------
; FDD_INIT_FLOPPY
;----------------------------------------------------------------------------
; Initialisiert alle Werte nach dem Wechsel einer Diskette.
; (cl<- = 0 - Fehler, 1 - OK)
fdd_init_floppy:
@fdd_login()
or cl,cl
jz fdd_init_floppy_in_use
; Testen, ob die Diskette gewechselt wurde:
call check_diskchange
or cl,cl
jnz fdd_init_floppy_disk_changed
; Die Diskette wurde nicht gewechselt, neuladen der Daten daher unnâtig.
mov cl,1
@fdd_logout()
ret
fdd_init_floppy_disk_changed:
push ax
push bx
push dx
push gs
push edi
mov ax,[_des_global_]
mov gs,ax
; Alle Buffer lâschen:
push cx
mov cx,8
mov edi,fdd_data_buffer_blocks
.reset_buffer_loop:
mov word ptr [edi],-1
add edi,2
loop .reset_buffer_loop
mov cx,[stdfdc_dma_buffer_base]
mov [stdfdc_dma_buffer],cx
pop cx
; Den Bootsektor laden (in den ersten Buffer):
@stdfdc_read_block(word num 0)
or cl,cl
jz fdd_init_floppy_error
xor edi,edi
mov di,[stdfdc_dma_buffer]
; Rooteintrâge:
gs:
mov ax,[edi+11]
mov [fdd_data_floppy_root_entrys],ax
; Sektoren/FAT:
gs:
mov ax,[edi+16]
mov [fdd_data_floppy_sectors_per_fat],ax
; Root-Startblock (FATs*Size of FAT)+hidden sectors+reserved sectors:
xor bx,bx
gs:
mov bl,[edi+10] ; Anzahl der FATs.
mul bx
gs:
add ax,[edi+0E]
gs:
add ax,[edi+1C]
mov [fdd_data_floppy_root_startblock],ax
; FAT-Startblock:
gs:
mov ax,[edi+0E]
mov [fdd_data_floppy_fat_startblock],ax
; Block Nummer 0 nun im 1. Buffer:
mov word ptr [fdd_data_buffer_blocks],0
add word ptr [stdfdc_dma_buffer],200
mov word ptr [fdd_data_next_buffer],1
pop edi
pop gs
pop dx
pop bx
pop ax
mov cl,1
@fdd_logout()
ret
fdd_init_floppy_error:
pop edi
pop gs
pop dx
pop bx
pop ax
xor cl,cl
@fdd_logout()
ret
fdd_init_floppy_in_use:
@add_error(dword num ERROR_FDD_IN_USE)
xor cl,cl
ret
;----------------------------------------------------------------------------
; FDD_LOGIN
;----------------------------------------------------------------------------
; Pr?ft, ob die Floppy gerade von jemand anderen benutzt wird. Wenn nicht,
; dann wird das aktuelle TSS eingetragen.
; (cl<- = 0 - Fehler, 1 - OK)
fdd_login_count: dd 0 ; Zâhler, wie oft der Benutzer sich einloggt.
@fdd_login(){
push cx
str cx
; Schon eingeloggt:
cmp [fdd_data_user],cx
jz .is_logged_in
cli ; Keine Interrupts, damit jetzt kein Taskwechesl kommt.
; Nein, ist das FDD frei:
cmp word ptr [fdd_data_user],0
jnz .error
mov [fdd_data_user],cx
sti
mov dword ptr [fdd_login_count],0
pop cx
mov cl,1
ret
.is_logged_in:
inc dword ptr [fdd_login_count]
pop cx
mov cl,1
ret
.error:
sti
pop cx
xor cl,cl
ret
}
;----------------------------------------------------------------------------
; FDD_LOGOUT
;----------------------------------------------------------------------------
; Gibt die Floppy wieder frei, wenn man der rechtmâáige Benutzer war.
@fdd_logout(){
push cx
str cx
cmp [fdd_data_user],cx
jz .logout
pop cx
ret
.logout:
cmp dword ptr [fdd_login_count],0
jz .now_logout
dec dword ptr [fdd_login_count]
pop cx
ret
.now_logout:
mov word ptr [fdd_data_user],0
pop cx
ret
}
;----------------------------------------------------------------------------
; FDD_READ_BLOCK
;----------------------------------------------------------------------------
; Liest den gew?nschten Block von der Disktette und kopiert ihn nach dest.
; (cl<- = 0 - Fehler, 1 - OK)
@fdd_read_block(word block,word dest_seg,dword dest_off){
~word is_block_in_buffer ; Gibt an, ob der Block tatsâchlich geladen wurde.
@fdd_login()
or cl,cl
jz .in_use
call fdd_init_floppy
or cl,cl
jnz .next
@fdd_logout()
ret
.next:
mov byte ptr [.is_block_in_buffer],1
; Testen, ob der Block im Buffer steht:
push ax
mov ax,[.block]
call fdd_find_block_buffer
pop ax
or cl,cl
jnz .no_load
mov byte ptr [.is_block_in_buffer],0
; Den Block lesen:
@stdfdc_read_block(word word ptr [.block])
or cl,cl
jz .error
.no_load:
@fdd_logout() ; Das FDD wird nun nicht mehr benâtigt.
; Nun den Block nach dest kopieren:
push es
push ax
push edi
mov ax,[.dest_seg]
mov es,ax
mov edi,[.dest_off]
push ecx
push esi
push ds
xor esi,esi
mov si,[stdfdc_dma_buffer]
mov ecx,80 ; (4 Bytes auf einmal)
mov ax,[_des_global_]
mov ds,ax
rep ; Achtung benutzt hier ecx!
movsd ; ds:esi -> es:edi
pop ds
cmp byte ptr [.is_block_in_buffer],1
jz .no_buffer_overrun
; Den erfolgreich gelesenen Block in den Buffer eintragen:
xor edi,edi
mov di,[fdd_data_next_buffer]
shl di,1 ; *= 2
add edi,fdd_data_buffer_blocks
mov ax,[.block]
mov [edi],ax
; Next Buffer um 1 erhâhen:
inc word ptr [fdd_data_next_buffer]
cmp word ptr [fdd_data_next_buffer],8
jnz .no_buffer_overrun
mov word ptr [fdd_data_next_buffer],0
.no_buffer_overrun:
pop esi
pop ecx
pop edi
pop ax
pop es
mov cl,1
ret
.error:
@fdd_logout()
xor cl,cl
ret
.in_use:
@add_error(dword num ERROR_FDD_IN_USE)
xor cl,cl
ret
}
;----------------------------------------------------------------------------
; FDD_WRITE_BLOCK
;----------------------------------------------------------------------------
; Schreibt 512 Bytes von scr in den gew?nschten Block.
; (cl<- = 0 - Fehler, 1 - OK)
@fdd_write_block(word block,word scr_seg,dword scr_off){
@fdd_login()
or cl,cl
jz .in_use
call fdd_init_floppy
or cl,cl
jnz .next
@fdd_logout()
ret
.next:
; Die 512 Byte von scr in den dma-Buffer kopieren:
push ds
push es
push ax
push edi
push ecx
push esi
xor edi,edi
; Den richtigen Buffer einstellen:
mov di,[fdd_data_next_buffer]
shl di,9
add di,[stdfdc_dma_buffer_base]
mov [stdfdc_dma_buffer],di
mov di,[stdfdc_dma_buffer]
mov ecx,80 ; (4 Bytes auf einmal)
mov ax,[_des_global_]
mov es,ax
mov esi,[.scr_off]
mov ax,[.scr_seg]
mov ds,ax
rep ; Achtung benutzt hier ecx!
movsd ; ds:esi -> es:edi
; Den Block schreiben:
@stdfdc_write_block(word word ptr [.block])
or cl,cl
jz .error
@fdd_logout() ; Das FDD wird nun nicht mehr benâtigt.
; Den erfolgreich geschriebenen Block in den Buffer eintragen:
xor edi,edi
mov di,[fdd_data_next_buffer]
shl di,1 ; *= 2
add edi,fdd_data_buffer_blocks
mov ax,[.block]
mov [edi],ax
; Next Buffer um 1 erhâhen:
inc word ptr [fdd_data_next_buffer]
cmp word ptr [fdd_data_next_buffer],8
jnz .no_buffer_overrun
mov word ptr [fdd_data_next_buffer],0
.no_buffer_overrun:
pop esi
pop ecx
pop edi
pop ax
pop es
pop ds
mov cl,1
ret
.error:
@fdd_logout()
pop esi
pop ecx
pop edi
pop ax
pop es
pop ds
xor cl,cl
ret
.in_use:
@add_error(dword num ERROR_FDD_IN_USE)
xor cl,cl
ret
}
;----------------------------------------------------------------------------
; FDD_FIND_BLOCK_BUFFER
;----------------------------------------------------------------------------
; Testet, ob der Block in ax schon im Buffer steht, wenn ja wird in cl 1
; zur?ckgegeben, und stdfdc_dma_buffer wird auf den entsprechenden Buffer
; gelegt, ansonsten wird in cl 0 zur?ckgegeben und stdfdc_dma_buffer wird
; auf den nâchsten Buffer zum Å¡berschreiben gelegt.
; (->ax = Block Nr,
; cl<- = 0 - nicht im Buffer)
fdd_find_block_buffer:
push cx
push edi
mov cx,8
mov edi,fdd_data_buffer_blocks
fdd_find_block_buffer_loop:
cmp [edi],ax
jz fdd_find_block_buffer_found
add edi,2
loop fdd_find_block_buffer_loop
mov di,[fdd_data_next_buffer]
shl di,9
add di,[stdfdc_dma_buffer_base]
mov [stdfdc_dma_buffer],di
pop edi
pop cx
xor cl,cl
ret
fdd_find_block_buffer_found:
sub edi,fdd_data_buffer_blocks
shl di,8 ; *= 256
add di,[stdfdc_dma_buffer_base]
mov [stdfdc_dma_buffer],di
pop edi
pop cx
mov cl,1
ret
;***************************************************************************
;*** STDFDC ***
;***************************************************************************
; Enthâlt Funktionen zum Steuern des FDC.
; ALLE FUNKTIONEN NUR ZUM INTERNEN GEBRAUCH!
; *** Drive Geometry ***
#define DG144_HEADS 2 ; heads per drive (1.44M)
#define DG144_TRACKS 50 ; number of tracks (1.44M) (80d)
#define DG144_SPT 12 ; sectors per track (1.44M) (18d)
#define DG144_GAP3FMT 54 ; gap3 while formatting (1.44M)
#define DG144_GAP3RW 1B ; gap3 while reading/writing (1.44M)
; *** I/O ports ***
#define FDC_DOR 3F2 ; Digital Output Register.
#define FDC_DRS 3F4 ; Data Rate Select Register (output).
#define FDC_MSR 3F4 ; Main Status Register (input).
#define FDC_DATA 3F5 ; Data Register.
#define FDC_DIR 3F7 ; Digital Input Register (input).
#define FDC_CCR 3F7 ; Configuration Control Register (output)
; *** Commands ***
#define CMD_SENSEI 08 ; sense interrupt status.
#define CMD_SPECIFY 03 ; specify drive timings.
#define CMD_SEEK 0F ; seek track.
#define CMD_RECAL 07 ; recalibrate.
#define CMD_VERSION 10 ; FDC version.
#define CMD_WRITE 0C5 ; write data (+ MT,MFM)
#define CMD_READ 0E6 ; read data (+ MT,MFM,SK)
#define CMD_FORMAT 04D ; format track (+ MFM)
; Adresse des DMA-Buffers (nur 16 Bit):
stdfdc_dma_buffer: dw 0
stdfdc_dma_buffer_base: dw 0
; Wenn der Counter 0 erreicht wird der Motor ausgeschaltet und der Counter
; wird auf -1 (FFFF) gesetzt (der Timerinterrupt zâhlt den Counter runter).
motor_kill_counter: dw 0
; *** Aktuelle drive geometry ***
drvgeom_heads: db 00 ; heads
drvgeom_tracks: db 00 ; tracks
drvgeom_spt: db 00 ; sectors per track
; *** DATEN ***
irq_0E_done: db 00 ; Gibt an, ob der IRQ 0E aufgerufen wurde.
motor_running: db 01 ; Motorstatus.
disk_changed: db 00 ; Gibt an, ob die Diskette gewechselt wurde.
status: db 00,00,00,00,00,00,00 ; Command-Result Bytes.
sr0: db 00 ; Status Register 0.
fdc_track: db 0FF ; Track, ?ber dem der Lesekopf gerade ist.
;----------------------------------------------------------------------------
; FDC_RESET
;----------------------------------------------------------------------------
; Den FDC zur?cksetzen.
; (bl<- = success)
fdc_reset:
pusha
; IRQ/DMA aus:
xor ax,ax
mov dx,FDC_DOR
out dx,al
; Motor sofort aus:
call motoroff_now
; Datenrate einstellen (500K/s):
mov dx,FDC_DRS
out dx,al
; Interrupts wieder aktivieren:
mov ax,0C
mov dx,FDC_DOR
out dx,al
; Der Reset erzeugt einen Interrupt. Diesen handeln:
mov bl,1
call waitfdc
cmp bl,0
jz reset_error
; Die Drive-Timings einstellen (aus dem BIOS entnommen):
mov bl,CMD_SPECIFY
call sendbyte
mov bl,0DF ; SRT = 3ms, HUT = 240ms
call sendbyte
mov bl,02 ; HLT = 16ms, ND = 0
call sendbyte
; Den "disk change" Status lâschen:
mov bl,1
call seek
cmp bl,0
jz reset_error
call recalibrate
cmp bl,0
jz reset_error
mov byte ptr [disk_changed],0
popa
mov bl,1
ret
reset_error:
call motoroff
popa
mov bl,0
ret
;----------------------------------------------------------------------------
; WAITFDC
;----------------------------------------------------------------------------
; (->bl = sense interrupt status / bl<- = Status)
; Wartet auf einen Interrupt vom FDC.
waitfdc:
pusha
mov di,bx
and di,0FF
; Warten bis der Interrupt vom FDC kommt:
sti
push eax
push ebx
mov ebx,[timer_tick]
waitfdc_loop:
cmp byte ptr [irq_0E_done],0
jnz waitfdc_weiter
; Auf Timeout pr?fen (max 500ms):
@calc_ticks(dword ebx)
cmp eax,50xD
jb waitfdc_loop
; Timeout:
pop ebx
pop eax
cli
popa
mov bl,0
ret
waitfdc_weiter:
pop ebx
pop eax
cli
; Command-Result Bytes einlesen (7 Bytes):
xor bx,bx
waitfdc_loop2:
mov dx,FDC_MSR
in al,dx
and al,10
cmp al,0
jz waitfdc_weiter2
cmp bx,7
jae waitfdc_weiter2
push bx
call getbyte
mov al,bl
pop bx
mov byte ptr [bx+status],al
inc bx
jmp waitfdc_loop2
waitfdc_weiter2:
cmp di,0
jz waitfdc_no_sensei
; Das Sense-Interrupt-Status Kommando senden:
mov bl,CMD_SENSEI
call sendbyte
call getbyte
mov byte ptr [sr0],bl
call getbyte
mov byte ptr [fdc_track],bl
waitfdc_no_sensei:
mov byte ptr [irq_0E_done],0
; Testen ob es einen Diskchange gab:
mov dx,FDC_DIR
in al,dx
and al,80
cmp al,0
jz waitfdc_weiter3
mov byte ptr [disk_changed],1
popa
mov bl,0
ret
waitfdc_weiter3:
popa
mov bl,1
ret
;----------------------------------------------------------------------------
; SENDBYTE
;----------------------------------------------------------------------------
; (->bl = Byte to send)
; Sendet das Byte in bl an den FDC.
sendbyte:
push cx
push dx
push ax
mov cx,80
mov dx,FDC_MSR
sendbyte_loop:
in al,dx
and al,0C0
cmp al,80
jnz sendbyte_weiter
mov dx,FDC_DATA
mov al,bl
out dx,al
pop ax
pop dx
pop cx
ret
sendbyte_weiter:
in al,80 ; delay
loop sendbyte_loop
pop ax
pop dx
pop cx
ret
;----------------------------------------------------------------------------
; GETBYTE
;----------------------------------------------------------------------------
; (bl<- = received Byte ( FF = Timeout ))
; Empfângt in bl ein Byte vom FDC.
getbyte:
push cx
push dx
push ax
mov cx,80
mov dx,FDC_MSR
getbyte_loop:
in al,dx
and al,0D0
cmp al,0D0
jnz getbyte_weiter
mov dx,FDC_DATA
in al,dx
mov bl,al
pop ax
pop dx
pop cx
ret
getbyte_weiter:
in al,80 ; delay
loop getbyte_loop
pop ax
pop dx
pop cx
mov bl,0FF ; Timeout
ret
;----------------------------------------------------------------------------
; RECALIBRATE
;----------------------------------------------------------------------------
; Den FDC rekalibrieren
; (bl<- = success)
recalibrate:
; Motor an:
call motoron
; Das Kommando zum Rekalibrieren sende:
mov bl,CMD_RECAL
call sendbyte
mov bl,0
call sendbyte
; Warten bis das Kommando ausgef?hrt wurde:
mov bl,1
call waitfdc ; Die R?ckgabe von waitfdc bleibt erhalten.
; Motor aus:
call motoroff
ret
;----------------------------------------------------------------------------
; MOTORON
;----------------------------------------------------------------------------
; Den Motor anschalten:
motoron:
; Lâuft der Motor schon:
cmp byte ptr [motor_running],0
jz motoron_weiter
ret
motoron_weiter:
push ax
push dx
push bx
; Den Motor starten:
mov dx,FDC_DOR
mov al,1C
out dx,al
; Den Kill-Counter nicht weiter runterzâhlen:
mov word ptr [motor_kill_counter],0FFFF
; Warten damit der Motor anlaufen kann:
@wait(dword num 50xD) ; 1/2 Sekunde.
mov byte ptr [motor_running],1
pop bx
pop dx
pop ax
ret
;----------------------------------------------------------------------------
; MOTOROFF
;----------------------------------------------------------------------------
; Den Motor stoppen:
motoroff:
; Steht der Motor schon:
cmp byte ptr [motor_running],0
jz motoroff_ende
; ca. 3 Sekunden warten und dann den Motor aus:
mov word ptr [motor_kill_counter],300xD
motoroff_ende:
ret
;----------------------------------------------------------------------------
; MOTOROFF_NOW
;----------------------------------------------------------------------------
; Den Motor SOFORT stoppen:
motoroff_now:
push ax
push dx
mov ax,0C
mov dx,FDC_DOR
out dx,al
mov byte ptr [motor_running],0
pop dx
pop ax
ret
;----------------------------------------------------------------------------
; SEEK
;----------------------------------------------------------------------------
; (->bl = track / bl<- = success)
; Den Lesekopf zum Track bl bewegen.
seek:
cmp byte ptr [fdc_track],bl
jnz seek_weiter
mov bl,1 ; Der Kopf ist schon da.
ret
seek_weiter:
push di
mov di,bx
; Den Motor starten:
call motoron
; Das Seek Kommando senden:
mov bl,CMD_SEEK
call sendbyte
mov bl,0
call sendbyte
mov bx,di
call sendbyte
; Warten bis das Seek Kommando ausgef?hrt ist:
mov bl,1
call waitfdc
cmp bl,0
jnz seek_weiter2
pop di
mov bl,0 ; Timeout!
ret
seek_weiter2:
; Den Kopf etwas Zeit geben:
@wait(dword num 50xD) ; 1/2 Sekunde warten.
; Motor aus:
call motoroff
; Testen ob der Kopf auch angekommen ist:
cmp byte ptr [sr0],20
jnz seek_error
mov bx,di
cmp byte ptr [fdc_track],bl
jnz seek_error
pop di
mov bl,1
ret
seek_error:
pop di
mov bl,0
ret
;----------------------------------------------------------------------------
; BLOCK2HTS
;----------------------------------------------------------------------------
; (->bx = Block
; bx<- = Head
; cx<- = Track
; dx<- = Sektor)
; Konvertiert die Eingabe von Blocks in head, track und sector.
block2hts:
; head = (block % (geometry.spt * geometry.heads)) / (geometry.spt);
; track = block / (geometry.spt * geometry.heads);
; sector = block % geometry.spt + 1;
push ax
push bp
pushw 0 ; head (bp+4)
pushw 0 ; track (bp+2)
pushw 0 ; sector (bp)
mov bp,sp
mov ah,0
mov al,[drvgeom_heads]
mov ch,0
mov cl,[drvgeom_spt]
mul cx
mov cx,ax
; *** ax = (geometry.spt * geometry.heads) ***
mov ax,bx
xor dx,dx
div cx
; *** ax = blocks / spt*heads dx = blocks % spt*heads ***
mov [bp+2],ax
mov ax,dx
mov ch,0
mov cl,[drvgeom_spt]
xor dx,dx
div cx
mov [bp+4],ax
; *** Errechnen des Sektors ***
mov ax,bx
div cl
add dx,1
mov [bp],dx
pop dx
pop cx
pop bx
pop bp
pop ax
ret
;----------------------------------------------------------------------------
; FDC_RW
;----------------------------------------------------------------------------
; (->bx = block nr
; ->cl = 1-read 0-write
; bl<- = 1 success)
; Liest oder Schreibt den Block Nr bx.
fdc_rw:
pusha
pushw 0 ; read/write (bp+6)
pushw 0 ; head (bp+4)
pushw 0 ; track (bp+2)
pushw 0 ; sector (bp)
mov bp,sp
mov [bp+6],cl
; Die logische Adresse in eine physikalische Adresse umwandeln:
call block2hts
mov [bp],dx
mov [bp+2],cx
mov [bp+4],bx
; Motor an:
call motoron
mov di,3 ; Max 3 Male probieren.
fdc_rw_loop:
; Testen, ob die Diskette gewechselt wurde:
mov dx,FDC_DIR
in al,dx
and al,80
cmp al,0
jz fdc_rw_no_diskchange
; Fehlgeschlagen, da die Diskette gewechselt wurde:
mov byte ptr [disk_changed],1
mov bl,1
call seek ; Disk Changed Staus ausschalten.
call recalibrate
call motoroff
add bp,8
mov sp,bp
popa
mov bl,0
@add_error(dword num ERROR_FD_CHANED_WHILE_RW)
ret
fdc_rw_no_diskchange:
; Den Kopf zum richtigen Track bewegen:
mov bl,[bp+2]
call seek
cmp bl,1
jz fdc_rw_seek_success
; Seek fehlgeschlagen:
call motoroff
add bp,8
mov sp,bp
popa
mov bl,0
@add_error(dword num ERROR_FD_SEEK_FAILED)
ret
fdc_rw_seek_success:
; Datenrate (500K/s) einstellen:
mov dx,FDC_CCR
mov bl,0
out dx,al
; Feststellen, was gemacht werden soll:
cmp byte ptr [bp+6],1
jnz fdc_rw_send_command_write
; Lesen:
mov bl,0 ; read
mov cx,200 ; 512 Bytes
call dma_xfer
mov bl,CMD_READ
call sendbyte
jmp fdc_rw_send_command_next
fdc_rw_send_command_write:
; Schreiben:
mov bl,1 ; write
mov cx,200 ; 512 Bytes
call dma_xfer
mov bl,CMD_WRITE
call sendbyte
fdc_rw_send_command_next:
; Alle Informationen ?ber die Position des Blocks ?bertragen:
mov bl,[bp+4] ; head
shl bl,2
call sendbyte
mov bl,[bp+2] ; track
call sendbyte
mov bl,[bp+4] ; head
call sendbyte
mov bl,[bp] ; sector
call sendbyte
mov bl,2 ; 512 Bytes/Sector
call sendbyte
mov bl,[drvgeom_spt]
call sendbyte
mov bl,DG144_GAP3RW ; gap 3 size for 1.44M read/write
call sendbyte
mov bl,0FF ; DTL = unused
call sendbyte
; Warten bis das Kommando ausgef?hrt wurde:
; (read/write braucht keinen sense interrupt status)
mov bl,0
call waitfdc
cmp bl,0
jnz fdc_rw_no_timeout
add bp,8
mov sp,bp
popa
mov bl,0 ; Timeout !
@add_error(dword num ERROR_FD_TIMEOUT_WHILE_RW)
ret
fdc_rw_no_timeout:
mov al,[status]
and al,0C0
cmp al,0
jz fdc_rw_worked
; Es hatt nicht funktioniert, nochmal:
call recalibrate
dec di
cmp di,0
jnz fdc_rw_loop
; *** ERROR ***
call motoroff
add bp,8
mov sp,bp
popa
mov bl,0
@add_error(dword num ERROR_FD_RW_FAILED)
ret
fdc_rw_worked:
; *** SUCCESS ***
call motoroff
add bp,8
mov sp,bp
popa
mov bl,1
ret
;----------------------------------------------------------------------------
; LOG_DISK
;----------------------------------------------------------------------------
; (bl<- = 1 = 1.44 Disk / 0 not supported)
; Feststellen um was f?r einen Diskettentyp es sich handelt.
log_disk:
push cx
call fdc_reset
cmp bl,0
jz log_disk_no_144
; Davon ausgehen, das es eine 1.44mb Diskette ist und Block 17 auf dem 1.
; Track lesen:
mov byte ptr [drvgeom_heads],DG144_HEADS
mov byte ptr [drvgeom_tracks],DG144_TRACKS
mov byte ptr [drvgeom_spt],DG144_SPT
mov bx,11 ; Block 17.
mov cl,1 ; Lesen.
call fdc_rw
cmp bl,0
jz log_disk_no_144
pop cx
mov bl,1
ret
log_disk_no_144:
pop cx
mov bl,0
@add_error(dword num ERROR_FD_TYP_NOT_SUPPORTED)
ret
;----------------------------------------------------------------------------
; DMA_XFER
;----------------------------------------------------------------------------
; (->bl = 1-read / 0-write
; ->cx = length)
; Aktiviert den DMA.
dma_xfer:
pusha
mov al,14 ; DMA1 deaktivieren
out 08,al
cmp bl,0
jnz dma_xfer_read
; *** Modus: Einzeltransfer, Adressinkrementierung, Schreiben, Kanal 2 ***
mov al,56
out 0B,al
jmp dma_xfer_weiter
dma_xfer_read:
; *** Modus: Einzeltransfer, Adressinkrementierung, Lesen, Kanal 2 ***
mov al,5A
out 0B,al
dma_xfer_weiter:
mov ax,[stdfdc_dma_buffer]
mov bx,[stdfdc_dma_buffer]
shr bx,4
shr bh,04
out 0C,al ; Flip-Flop zur?ckstellen
out 04,al ; Niederwertige Adresse ausgeben
mov al,ah
out 04,al ; Hâherwertige Adresse ausgeben
mov al,bh
out 81,al ; Segment ausgeben
out 0C,al ; Flip-Flop zur?cksetellen
; *** Length -1 ***
dec cx
mov al,cl ; Low-Byte
out 05,al
mov al,ch ; High-Byte
out 05,al
mov al,02 ; Kanal 2 freigeben
out 0A,al
mov al,10 ; DMA 1 aktivieren
out 08,al
popa
ret
;***************************************************************************
;*** FUNKTIONEN ***
;***************************************************************************
;----------------------------------------------------------------------------
; STDFDC_IRQ_HANDLER
;----------------------------------------------------------------------------
; Wird vom FDC-IRQ ausgelâst.
stdfdc_irq_handler:
cli
push ax
push ds
cs:
mov ax,[_des_kernel_data_]
mov ds,ax
mov byte ptr [irq_0E_done],1
push es
mov ax,[_des_vram_]
mov es,ax
es:
mov byte ptr [(160xD*4)],'H'
es:
inc byte ptr [(160xD*4+2)]
pop es
; Dem Controller mitteilen, dass der IRQ bearbeitet wurde:
mov al,20
out 20,al
pop ds
pop ax
sti
iret
;----------------------------------------------------------------------------
; STDFDC_READ_BLOCK
;----------------------------------------------------------------------------
; Liest einen Block (512 Byte) in den aktuellen DMA Buffer ein..
; Gibt in cl 1 zur?ck wenn es funktioniert hat, sonst 0.
@stdfdc_read_block(word block){
push ax
push bx
push dx
cli ; Bei FDC Funktionen besser keine Interrupts.
; Testen, ob die Diskette gewechselt wurde:
call check_diskchange
or cl,cl
jnz .log_disk ; Diskette wurde gewechselt.
; Ggf die Diskette testen:
cmp byte ptr [drvgeom_tracks],0
jnz .no_log_disk
.log_disk:
call log_disk
cmp bl,0
jz .error
.no_log_disk:
; Den Block lesen:
mov bx,[.block] ; Block nr.
mov cl,1 ; read
call fdc_rw
cmp bl,0
jz .error
sti
pop dx
pop bx
pop ax
mov cl,1
ret
.error:
sti
pop dx
pop bx
pop ax
mov cl,0
ret
}
;----------------------------------------------------------------------------
; STDFDC_WRITE_BLOCK
;----------------------------------------------------------------------------
; Schreibt 512 Bytes aus dem aktuellen DMA Buffer auf den angegebenen Block.
; Gibt in cl 1 zur?ck wenn es funktioniert hat, sonst 0.
@stdfdc_write_block(word block){
push ax
push bx
push dx
cli ; Bei FDC Funktionen besser keine Interrupts.
; Testen, ob die Diskette gewechselt wurde:
call check_diskchange
or cl,cl
jnz .log_disk ; Diskette wurde gewechselt.
; Ggf die Diskette testen:
cmp byte ptr [drvgeom_tracks],0
jnz .no_log_disk
.log_disk:
call log_disk
cmp bl,0
jz .error
.no_log_disk:
; Den Block schreiben:
mov bx,[.block] ; Block nr.
mov cl,0 ; write
call fdc_rw
cmp bl,0
jz .error
sti
pop dx
pop bx
pop ax
mov cl,1
ret
.error:
sti
pop dx
pop bx
pop ax
mov cl,0
ret
}
;----------------------------------------------------------------------------
; CHECK_DISKCHANGE
;----------------------------------------------------------------------------
; ->cl = Gibt eine 1 zur?ck, wenn die Diskette gewechselt wurde.
check_diskchange:
push dx
push ax
; Kommando senden, damit das DIR die Informationen ?ber den Diskchange hat:
call motoron
call motoroff
mov dx,FDC_DIR
in al,dx
and al,80
mov cl,al
pop ax
pop dx
ret
Nicht wundern über die seltsame Syntax, hab ich für meinen eigenen Assembler, den MMASM geschrieben (man arbeitet doch am liebsten mit den eigenen Werkzeugen, nich :wink: ).
Bei Bedarf hab ich sowas ähnliches auch noch in C.
MM
-
Wenn der C Code auch in der Lage ist, zu lesen und zu schreiben wär er ganz interessant :D
-
Grüß dich, lies dir das hier mal an:
http://www.xaff.org/GI/floppy.html
-
Meine Version des C Codes finde ich irgendwie grad nicht, aber dafür hab ich hier nen Link zu nem netten Democode, mit dem man sogar Disketten formatieren kann (aus dem FreeDOS32):
http://www.koders.com/c/fidCACDE05FE2F07441CF52B2104E08993FF8E8D8B5.aspx
Mir ist das zwar etwas zu unübersichtlich, aber eventuell hilft es weiter.
Ich hatte meinen Code übrigends nach der folgenden FDC Referenz geschrieben:
http://www.isdaman.com/alsos/hardware/fdc/floppy.htm
Eventuell finde ich meinen C Code ja nochmal wieder...
MM
-
Vielen dank für eure Informationen. Also der IRQ6 und die Ports 3F0h-3F7h und 370h-377h benötige ich um mit der Diskette zu komonizieren. Aber ich habe das leider nicht so ganz verstanden. Was muss der Code des IRQ6 denn machen? Und wie lese/schreibe ich Sektoren. Beispiel:
Ich möchte den Sektor 3 der Diskette im ersten Diskettenlaufwerk in den Arbeitsspeicher an Adresse 20000h schreiben. Wie würde der Code dafür aussehen? Gibt es dazu eigentlich auch deutsche Seiten? So wie ich das sehe, werden also max. 4 Diskettenlaufwerke unterstützt. Wann benötige ich den ersten Kontroller (3F0-3F7) und wann den zweiten (370-377)?
Danke!!!
PS:
Grüß dich, lies dir das hier mal an:
http://www.xaff.org/GI/floppy.html
Der Link funktioniert nicht.
-
Wann benötige ich den ersten Kontroller (3F0-3F7) und wann den zweiten (370-377)?
Naja, den ersten Kontroller benutzt du fürs erste Floppy und den zweiten Kontroller fürs zweite Floppy. :|
-
Wann benötige ich den ersten Kontroller (3F0-3F7) und wann den zweiten (370-377)?
Naja, den ersten Kontroller benutzt du fürs erste Floppy und den zweiten Kontroller fürs zweite Floppy. :|
Und fürs dritte und Vierte Floppy?
-
Nein, vergiss was ich gesagt habe. :/
Die max. 4 Floppys steuert man ja alle über die selben Register an.
The base port address used for the controller is dependant on whether the controller is configured as the primary or secondary controller
Mehr kann ich dir dazu leider nicht sagen als das was in den Docs steht.
[edit]Das ist so wie: Die größe des Speichers hängt von der eingebauten Menge des Speicher ab.[/edit]
-
Ich hab meins jetzt auch zum Laufen gebracht. Fehler war, dass ich nicht lange genug gewartet hab, bis das Teil fertig hatte. ;)
An dieser Stelle möchte ich nocheinmal ein herzliches Dankeschön an die Entwickler von Intel für diesen grandiosen Anti-Logik-Test richten. Sie haben ihr Ziel erreicht und es geschaft, einen Baustein zu entwickeln, der eine Unlogik enthält, wie sie noch nie gesehen wurde.
-
@[MM]: Ich habe mir mal deinen Code angeschaut. Schon in denn ersten Zeilen gibt es eine Variable/Pointerkonstante (hw_fdc) die nirgends deklariert wurde!?
Fehlt da eventuell noch was?
-
hw_fdd und hw_floppys sind Variablen aus der Hardwareerkennung, in hw_fdd steht glaub ich die Versionsnummer des FDD-Controllers und in hw_floppys die Anzahl der Floppys.
Wie das initialisiert wurde dürfte für dieses Thema unerheblich sein.
MM
-
Ich denke die Hardwareerkennung der Floppy ist hier schon relevant.
Ok, meistens ist nur eine einziges 3 1/2 Floppy am PC angeschlossen aber ein OS sollte doch auch mit allen anderen Fällen zurechtkommen.
Und wenn ein OS sich beim Booten aufhängt nur weil dem Floppytreiber kein formgerechtes Standardgerät vor die Nase gesetzt wurde... :?
Währe also nett wenn Du eventuell auch deinen Hrdwareerkennungscode für die Floppy postest. :D
-
Gna, immer diese Extrawünsche...
Aber gut, hier der Code mit dem bei diesem Projekt der Floppy-Controller gesucht wurde:
detect_basic_hw_string: db "detecting basic hardware: ",0A,0D,0
create_temp_pmode_env: db "creating temporary pmode environment... ",0
start_pmode: db "starting protected mode... ",0
hw_start:
hw_cpu_id_string: dd 0,0,0 ; Prozessor ID-String (o0 l13).
db 0
hw_cpu_version: dd 0 ; Informationen ?ber die Version (o13 l4).
hw_cpu_features: dd 0 ; Informationen ?ber die Features (o17 l4).
hw_cpu_speed: dd 0 ; ungefâhre MHz Zahl (o21 l4).
hw_memory: dd 0 ; KB an Speicher (o25 l4).
hw_fdc: db 0 ; 0=none / 1=extended fdc (o29 l1).
hw_floppys: db 0 ; Anzahl der Floppylaufwerke (o30 l1).
; Path des Bootscripts (o31 l72).
bootscript_path: db ".......................................................................",0
#define HW_SIZE 103xD
; *** PREPARE_KERNEL ***
prepare_kernel:
; Hardware suchen:
mov si,detect_basic_hw_string
call print_string
call detect_processor
call detect_memory
call detect_fdc
call detect_floppys
; Den Temp-Pmode vorbereiten:
mov si,create_temp_pmode_env
call print_string
jmp temp_pm
; *** DETECT_FDC ***
#define FDC_DATA 3F5 ; Data Register.
#define FDC_MSR 3F4 ; Main Status Register (input).
#define CMD_VERSION 10 ; FDC version.
detect_fdc_string: db " floppy disk controller: ",0
detect_fdc_ec_found: db "extended controller",0A,0D,0
detect_fdc_no_ec_found: db "none",0A,0D,0
detect_fdc:
mov bl,COLOR_WHITE
mov si,detect_fdc_string
call print_string_color
; Testet, welche FDC-Version installiert ist:
mov bl,CMD_VERSION
call sendbyte_fdc
call getbyte_fdc
cmp bl,90
jnz detect_fdc_no_ec
mov si,detect_fdc_ec_found
call print_string
mov byte ptr [hw_fdc],1
ret
detect_fdc_no_ec:
mov si,detect_fdc_no_ec_found
call print_string
mov byte ptr [hw_fdc],0
ret
; *** SENDBYTE_FDC ***
; (->bl = Byte to send)
; Sendet das Byte in bl an den FDC.
sendbyte_fdc:
push cx
push dx
push ax
mov cx,80
mov dx,FDC_MSR
sendbyte_fdc_loop:
in al,dx
and al,0C0
cmp al,80
jnz sendbyte_fdc_weiter
mov dx,FDC_DATA
mov al,bl
out dx,al
pop ax
pop dx
pop cx
ret
sendbyte_fdc_weiter:
in al,80 ; delay
loop sendbyte_fdc_loop
pop ax
pop dx
pop cx
ret
; *** GETBYTE_FDC ***
; (bl<- = received Byte ( FF = Timeout ))
; Empfângt in bl ein Byte vom FDC.
getbyte_fdc:
push cx
push dx
push ax
mov cx,80
mov dx,FDC_MSR
getbyte_fdc_loop:
in al,dx
and al,0D0
cmp al,0D0
jnz getbyte_fdc_weiter
mov dx,FDC_DATA
in al,dx
mov bl,al
pop ax
pop dx
pop cx
ret
getbyte_fdc_weiter:
in al,80 ; delay
loop getbyte_fdc_loop
pop ax
pop dx
pop cx
mov bl,0FF ; Timeout
ret
; *** DETECT_PROCESSOR ***
detect_processor_string: db " processor: ",0
detect_processor_speed_string1: db " ~",0
detect_processor_speed_string2: db "MHz",0A,0D,0
detect_processor:
mov si,detect_processor_string
mov bl,COLOR_WHITE
call print_string_color
; Den ID-String holen (12 Bytes in ebx,edx,ecx):
xor eax,eax
cpuid
mov [hw_cpu_id_string],bl
shr ebx,8
mov [(hw_cpu_id_string+1)],bl
shr ebx,8
mov [(hw_cpu_id_string+2)],bl
shr ebx,8
mov [(hw_cpu_id_string+3)],bl
shr ebx,8
mov [(hw_cpu_id_string+4)],dl
shr edx,8
mov [(hw_cpu_id_string+5)],dl
shr edx,8
mov [(hw_cpu_id_string+6)],dl
shr edx,8
mov [(hw_cpu_id_string+7)],dl
shr edx,8
mov [(hw_cpu_id_string+8)],cl
shr ecx,8
mov [(hw_cpu_id_string+9)],cl
shr ecx,8
mov [(hw_cpu_id_string+0A)],cl
shr ecx,8
mov [(hw_cpu_id_string+0B)],cl
mov si,hw_cpu_id_string
call print_string
; Erweiterte Informationen holen:
xor eax,eax
inc ax
cpuid
mov [hw_cpu_version],eax
mov [hw_cpu_features],edx
; CPU Geschwindigkeit ermitteln:
call detect_cpu_speed
mov si,detect_processor_speed_string1
call print_string
mov eax,[hw_cpu_speed]
mov ebx,10xD
call print_number
mov si,detect_processor_speed_string2
call print_string
ret
detect_cpu_speed_lo: dd 0
detect_cpu_speed_hi: dd 0
detect_cpu_speed_delay: dd 0
detect_cpu_speed:
; Aktuelle Cycle Zahl holen:
db 0F,31 ; RDTSC
mov [detect_cpu_speed_lo],eax
mov [detect_cpu_speed_hi],edx
; Delay von ca. 500ms:
xor ax,ax
int 1A
shl ecx,16xD
mov cx,dx
mov [detect_cpu_speed_delay],ecx
add dword ptr [detect_cpu_speed_delay],9
detect_cpu_speed_delay_loop:
int 1A
shl ecx,16xD
mov cx,dx
cmp [detect_cpu_speed_delay],ecx
jg detect_cpu_speed_delay_loop
; Jetzt aktuelle Cycle Zahl holen und die alte davon abziehen:
db 0F,31 ; RDTSC
sub eax,[detect_cpu_speed_lo]
sbb edx,[detect_cpu_speed_hi]
; Einen kleinen Korrekturwert hinzuf?gen:
add eax,600000
adc edx,0
; Nun ausrechnen wie viele Cycle der Rechner in 1000 Sekunden macht (MHz):
mov ecx,7A120
div ecx
mov [hw_cpu_speed],eax
ret
; *** DETECT_MEMORY ***
detect_memory_string1: db " memory: ",0
detect_memory_string2: db "kb",0A,0D,0
detect_memory:
mov si,detect_memory_string1
mov bl,COLOR_WHITE
call print_string_color
; Dieser Interrupt gibt die Menge an Erweiterungsspeicher in kb zur?ck:
mov eax,0E801
int 15
; Es kann sein, dass âltere BIOS-Versionen diese Funktion noch nicht haben:
jc detect_memory_noE801
and eax,0FFFF ; 16-Bit mem unter 16mb in 1kb Blâcken.
and ebx,0FFFF ; 16-bit mem ?ber 16mb in 64kb Blâcken.
shl ebx, 6 ; Auf 1kb Blâcke bringen.
add eax,ebx
mov [hw_memory],eax
jmp detect_memory_ende
detect_memory_noE801:
; Die Speichergrâáe aus dem CMOS lesen:
mov al,17
out 70,al
in al,71
mov [hw_memory],al
mov al,18
out 70,al
in al,71
mov [(hw_memory+1)],al
detect_memory_ende:
; Den gesammten Speicher nicht nur den Erweiterten (also +1mb):
add dword ptr [hw_memory],1024xD
mov eax,[hw_memory]
mov ebx,10xD
call print_number
mov si,detect_memory_string2
call print_string
ret
; *** DETECT_FLOPPYS ***
detect_floppys_string: db " floppy disks: ",0
detect_floppys:
mov si,detect_floppys_string
mov bl,COLOR_WHITE
call print_string_color
; Floppy 1 testen:
push es
mov ax,800
xor dx,dx
int 13
pop es
jc detect_floppys_done ; Error.
cmp cx,0
je detect_floppys_done ; Nicht installiert.
inc byte ptr [hw_floppys]
; Floppy 2 testen:
push es
mov ax,800
mov dx,1
int 13
pop es
jc detect_floppys_done ; Error.
cmp cx,0
je detect_floppys_done ; Nicht installiert.
inc byte ptr [hw_floppys]
detect_floppys_done:
xor eax,eax
mov al,[hw_floppys]
mov ebx,10xD
call print_number
mov si,new_line
call print_string
ret
detect_fdc wird prüfen, ob eine Floppy da ist und detect_floppys prüft, ob 1 oder 2 Laufwerke installiert sind (glaub ich). Die anderen Funktionen sind für so Zeug wie Prozessorerkennung usw...
MM
-
Wäre gut wenn jemand ein Tutorial dazu schreiben würde. ;)
-
Ich habe oft gelesen, dass man DMA nicht benutzen sollte. Ich verstehe aber nicht warum. Hat das einen Nachteil? Geht das überhaupt ohne? Und dann hätte ich noch eine Frage. Was muss im IRQ6 passieren? Also was muss der IRQ6 machen wenn er aufgerufen wird?
Danke!!!
-
Nun den, IRQ & DMA haben einen Nachteil:
Du kannst nur die ersten 16 MB (physikalisch) addressieren, zudem ist es viel zu aufwendig.
Vor allem ist die implementierung ziemlich schwierig...
DMA kann zu dem nicht 32 Bit arbeiten, nur die Register 0-5 oder so...
verstehe ich nicht :(
-
Auch wenn man mit dem DMA für floppy nur im unteren Speicherbereich arbeiten kann würde ich diese Methode vorziehen, denn PIO mit dem FDC ist ein CPU fresser und nichts im Vergleich zu dem was benötigt wird um ein par KB von A nach B zu kopieren.
-
Also mal konkret bitte. Welcher vorteile hat DMA und welche Nachteile hat DMA. Und was muss der Code des IRQ6 machen?
Danke!!!
-
Vorteile:
- der Übertragungsvorgang verläuft automatisch
- du musst den Übertragungsvorgang nicht überwachen
- du kannst während der Übertragung andere Tasks an den Prozessor lassen
Nachteile:
- du kannst nur die unteren 16 MB im Speicher adressieren, sodass du in den meisten Fällen den Sektor in einen gesicherten Bereich kopieren und von dort aus dann in den Programmbereich kopieren musst
-
Man sollte auf jeden Fall DMA verwenden, das hat den Vorteil, das man wärend der Datenübertragung noch andere Sachen mit der CPU machen kann, und es viel schneller ist als PIO.
Man kann ja die ersten 16 MB für DMA reservieren, dann hat man kein Problem mit den 16 MB. Wenn diese 16 MB bereits voll sind, kann man ja immernoch PIO als Alternative benutzen. Selbst das kopieren in den oberen Speicherbereich ist eventuell schneller, da man beim kopieren in DWORDs verarbeiten kann, beim PIO kann man aber meist nur einzelne Bytes lesen.
-
Vielen dank, ich werde also DMA verwenden (ich arbeite sowieso im 16 Bit PM, also max. 16 MByte ;) )
Aber was muss der Code des IRQ6 machen?
Danke!!!
-
Man sollte auf jeden Fall DMA verwenden, das hat den Vorteil, das man wärend der Datenübertragung noch andere Sachen mit der CPU machen kann, und es viel schneller ist als PIO.
Man kann ja die ersten 16 MB für DMA reservieren, dann hat man kein Problem mit den 16 MB. Wenn diese 16 MB bereits voll sind, kann man ja immernoch PIO als Alternative benutzen. Selbst das kopieren in den oberen Speicherbereich ist eventuell schneller, da man beim kopieren in DWORDs verarbeiten kann, beim PIO kann man aber meist nur einzelne Bytes lesen.
Ich würds auch verwenden (tu ich auch ;)), auch, weil bei der Übertragung per DMA keine Daten verlohren gehen. Bei dem anderen kann es sein, dass, wenn der Task durch einen Taskwechsel unterbrochen wird (was fast immer so sein sollte), Daten verlohren gehen, weil der FDC sich nicht kümmert, ob seine Daten ankommen. (Soweit ich weiß...)
-
Nicht wenn man es ordentlich programmiert.
Aber dann wird für jedes Byte ein Int aufgerufen was die ganze sache ja so langsam macht. Z. B. Win95 (glaube auch 98 ) benutzt kein DMA für die Floppy, das kann man auch gut erkennen wenn das System ausgelastet ist nur weil man was mit der Floppy macht.
Damals bei "Betriebssystemen" wie Dos war das kein Problem denn man musste sowieso warten bis alle Daten gelesen oder geschrieben waren.
Aber bei Multitaskingsystemen kam erschwerend die komplexere Int verarbeitung des PM hinzu.
Ich hab mal ausprobiert wie schnell eine fd daten lesen kann.
Für eine ganze fd benötigt ich 42 Sec.
1440 KB = 1474560 Byte
1474560 / 42 = ~35108 Ints. pro Sec.
-
OK, wie gesagt werde ich es auch mit DMA machen. Ich habe herausgefunden, dass der IRQ6 Code ledinglich zeigen soll das er aufgerufen wurde. Dies kann er z.B. in dem er den Wert 1 in einer Variable abspeichert. Dann kann man später mit cmp variable,1 prüfen ob der IRQ6 aufgerufen wurde. Dann habe ich auch herausgefunden das ich neun Bytes an dem 3F5h senden muss, um Sektoren schreiben/lesen zu können. Aber wie genau mach ich das jetzt mit DMA? Ich meine wo muss ich die Adresse angeben, wo er mir den Sektor hinkopieren soll?
Danke!!!
PS: Und warum gibt es zwei Controller?
-
Um DMA zu benutzen musst du den DMA Chip ansprechen. Ich habe hier mal ein bisel Code meines "Treibers" herausgesucht, aber das meiste habe ich nur irgendwoher Copy&Past. :roll:
;DMA channel 0-3 command register
mov al,00010100b
;|||||1=controller; 0=memory-to-memory
;||||1=compressed timing; 0=normal timing
;|||1=rotating priority; 0=fixed priority
;||1=extended write selection; 0=late write selection
;|1=DREQ sense active high; 0=low
;1=DACK sense active high; 0=low
out 0x8,al
;DMA channel 0-3 mode register
mov al,01010110b
;||||||XX:channel select 0..3
;||||XX:00=Verify transfer; 01=Write transfer; 10=Read transfer
;|||1=NonAutoinitialized
;||X:Address increment(0=+;1=-)
;XX:00=Demand mode; 01=Single mode; 10=Block mode; 11=Cascade mode
out 0xB,al
out 0xC,al ;DMA clear byte pointer flip-flop(only write something)
mov eax,floppy_buffer+0x500 ;0x10000?
out 0x4,al ;linear @ 0-7
shr eax,8
out 0x4,al ;linear @ 8-15
shr eax,8
out 0x81,al ;linear @ 16-23
out 0xC,al ;DMA clear byte pointer flip-flop
mov al,0xff
out 0x5,al
mov al,0x1
out 0x5,al ;load 511 into count register (to read one sector)
; it should be noted that for multiple transfers, the
; second value output to port 05h is equivalent to
; (2*number of sectors)-1
mov al,0x2
out 0xa,al ;release channel 2
;enable DMA 1
mov al,0x10
out 0x8,al ;this is the value for enabling the DMA for the mode required
Zusätzlich muss man dem FDC noch sagen das er DMA benutzen soll:
mov al,3;= Fix Drive Data
call floppy_write
mov al,0x0F
; |x=head unload time
; x = step rate
call floppy_write
;head unload time
;| 1M 500k 300k 250k (Data Transfer Rate)
;0 128 256 426 512
;1 8 16 26.7 32
;2 16 32 53.3 64
;. .... .... .... ....
;E 112 224 373 448
;F 120 240 400 480
;step rate
;| 1M 500k 300k 250k (Data Transfer Rate)
;0 8.0 16 26.7 32
;1 7.5 15 25.0 30
;2 7.0 14 23.3 28
;. .... .... .... ....
;E 1.0 2 3.3 4
;F 0.5 1 1.7 2
mov al,00000010b
;|||||||x 0=DMA 1=noDMA
;xxxxxxx = head load time
call floppy_write
;head load time
; | 1M 500k 300k 250k (Data Transfer Rate)
; 0 128 256 426 512
; 1 1 2 3.3 4
; 2 2 4 6.6 8
;.. .... .... .... ....
;7E 126 252 420 504
;7F 127 254 423 508
Das was da steht muss nicht umbeding Fehlerfrei sein, aber wir sollten alle Informationen zusammentragen um das Geheimniss FDC zu lüften. : D
*denktübereingroßestuorialnach*
-
danke
Also der Obere Code zur DMA steht auch so in meinem PC Hardwarebuch. Das werde ich mir jetzt genaustens durchlesen. Das mit dem DMA an FDC: Und was ist mit der Funktion "floppy_write"?
*denktübereingroßestuorialnach*
Das wäre echt super.
Danke!!!
-
*denktübereingroßestuorialnach*
Das wäre echt super.
So eins habe ich vor längerer Zeit einmal angefangen, mal sehen, ob ich das weitermache. Wenn jemand ein Tut schreiben will, kann ich ihm gerne meine Anfänge als Stütze geben.
-
Also der Obere Code zur DMA steht auch so in meinem PC Hardwarebuch. Das werde ich mir jetzt genaustens durchlesen. Das mit dem DMA an FDC: Und was ist mit der Funktion "floppy_write"?
*denktübereingroßestuorialnach*
Das wäre echt super.
Danke!!!
Ich unterschlagen halt auch mal was. 8)
floppy_write: ;data port=al
push ax
mov dx,0x3F4
.loop1:
in al,dx
and al,11000000b
cmp al,10000000b
;|X:1=FDC to CPU; 0=CPU to FDC
;X :data reg ready
jne .loop1
inc dx
pop ax
out dx,al
ret
@joachim_neu:
Ja, alles was man an Infos sammel kann ist gut. Wenn es zu groß zum posten ist bitte als Email: osbios at web . de
Ich habe mir schon mal Gedanken über den Inhalt gemacht:
-BIOS Diskettenfunktionen
-Programmierbeispiele (Mit Ablaufdiagram?)
-Sonstiges (Tipps, Bugs, Besonderheiten, ...)
-Befehlsliste der BIOS-Funktionen
-direkte Programmierung des Diskettenlaufwerkkontrollers
-Kontroller Modele
-Register/Ports
-Interrupt
-DMA
-Programmierbeispiele (Mit Ablaufdiagram?)
-Sonstiges (Tipps, Bugs, Besonderheiten, ...)
-Befehlsliste für den FDC
Also eine ausführliche Dok. für Programmierer. Oder soll man gleich in die Vollen gehen und alles was man zu Floppys finden kann als THE ULTIMATIVFLOPPYDOKU titulieren? ^^
Auf jeden fall will ich auch solche sachen wie DMA soweit erklähren, dass man deren Benutzung im Zusammenhang mit der Floppy ohne extra Tuts verstehen kann.
Eventuell noch Ideen was fehlt?
-
Wenn du schon DMA machst, dann auch richtig ausführlich. Du kannst es ja 2teilig machen, wenn du Lust hast. Erst DMA und dann FDC mit Benutzung von DMA.
-
Ich habe schon darüber nachgedacht nicht alles in eine Dokumentation reinzustopfen, aber aus Sicht eines Programmierers der die Floppy programmieren will ist ein einzelne Dok. mit allen nötigen Infos natürlich nicht schlecht. Der Programmierer hat daduch auch mehr Übersicht, da z.B. für Floppy mit DMA nicht alles über DMA-Programmiererung enthalten sein muss.
Naja, dann werde ich micht mal selber ransetzn und ersteinmal Informationen zusammensuchen. Wenn ich einen besseren Überblick habe kann ich die einzelnen Bereiche besser abgrenzen.
-
Also ich wäre wirklich sehr dankbar für ein ausführliches Tutorial zu diesem Thema. Im Moment verstehe ich nämlich nur Bahnhof.
-
@[MM]: Also ich glaube das bei deinem Code irgendwie was fehlt. Z.b. bei motoroff. Wo wird denn da der Motor ausgeschalten? Und ca. 3 Sekunden wird dort auch nicht gewartet. motoroff_now verstehe ich ja aber motoroff nicht. Da felt doch was, richtig?
-
Nur, um es mal gesagt zu haben:
Es ist theoretisch auch möglich, das RM Int 13 im PM weiterzuverwenden. Wie? Nun, man macht sich einen Task, schaltet den in den VM86, mappt ihm alles, wie ers im RM hätte und öffnet die notwendigen FDC-Ports im IO-Bitmap des TSS. So kann ein RM-Treiber in einem emulierten RM weiterhin die RM-Ints benutzen und man erspart sich das Programmieren.
-
Nur, um es mal gesagt zu haben:
Es ist theoretisch auch möglich, das RM Int 13 im PM weiterzuverwenden. Wie? Nun, man macht sich einen Task, schaltet den in den VM86, mappt ihm alles, wie ers im RM hätte und öffnet die notwendigen FDC-Ports im IO-Bitmap des TSS. So kann ein RM-Treiber in einem emulierten RM weiterhin die RM-Ints benutzen und man erspart sich das Programmieren.
Das will ich aber nicht. ;)
-
Nur, um es mal gesagt zu haben:
Es ist theoretisch auch möglich, das RM Int 13 im PM weiterzuverwenden. Wie? Nun, man macht sich einen Task, schaltet den in den VM86, mappt ihm alles, wie ers im RM hätte und öffnet die notwendigen FDC-Ports im IO-Bitmap des TSS. So kann ein RM-Treiber in einem emulierten RM weiterhin die RM-Ints benutzen und man erspart sich das Programmieren.
ich kenn eine einfachere methode: man schreibt einen RM-Code->PM-Code konverter, der auf binärcode-ebene arbeitet. den jagt man dann vor dem ersten benutzen des int 13h über eben diesen rüber. dann muss man den interrupt nur noch in die IDT eintragen. so einfach ist das :P
-
Hi,
ich habe noch eine Frage. Ich kann mit dem 3F4h und 3F7h die Datenrate einstellen. Aber was ist da der unterschied bzw. wann sollte ich welches Register benutzen.
Danke!!!
-
Nur, um es mal gesagt zu haben:
Es ist theoretisch auch möglich, das RM Int 13 im PM weiterzuverwenden. Wie? Nun, man macht sich einen Task, schaltet den in den VM86, mappt ihm alles, wie ers im RM hätte und öffnet die notwendigen FDC-Ports im IO-Bitmap des TSS. So kann ein RM-Treiber in einem emulierten RM weiterhin die RM-Ints benutzen und man erspart sich das Programmieren.
Das will ich aber nicht. ;)
Ich habs nur der Vollständigkeit wegen gesagt. Es soll ja auch andere Leute geben, die vor dem Problem stehen (werden) und die Such-Funktion benutzen. ;)
Nur, um es mal gesagt zu haben:
Es ist theoretisch auch möglich, das RM Int 13 im PM weiterzuverwenden. Wie? Nun, man macht sich einen Task, schaltet den in den VM86, mappt ihm alles, wie ers im RM hätte und öffnet die notwendigen FDC-Ports im IO-Bitmap des TSS. So kann ein RM-Treiber in einem emulierten RM weiterhin die RM-Ints benutzen und man erspart sich das Programmieren.
ich kenn eine einfachere methode: man schreibt einen RM-Code->PM-Code konverter, der auf binärcode-ebene arbeitet. den jagt man dann vor dem ersten benutzen des int 13h über eben diesen rüber. dann muss man den interrupt nur noch in die IDT eintragen. so einfach ist das :P
Das wird nicht so einfach sein. Du musst die ganzen Adressen neu berechnen und den Code manipulieren. Außerdem musste (wie schon gesagt) alles von 16 bit zu 32 bit bringen. Da finde ich das andere einfacher, auch, weils sicherer ist. ;)
-
Ich würde generell vermeiden, den VM86 Mode zu nutzen, und ihn nur dann nutzen, wenn es unbedingt nötig ist (VESA Framebuffer z.B.). Er ist unportabel (x86_64 unterstützt ihn nicht mehr), switches zurück in den Realmode sind leichter, und das BIOS ist meistens auch nicht gerade bugfrei.
-
Ich würde generell vermeiden, den VM86 Mode zu nutzen, und ihn nur dann nutzen, wenn es unbedingt nötig ist (VESA Framebuffer z.B.). Er ist unportabel (x86_64 unterstützt ihn nicht mehr), switches zurück in den Realmode sind leichter, und das BIOS ist meistens auch nicht gerade bugfrei.
1. Wenn du nach Portabilität gehst, kannst du den PM vergessen, den gibt es auch nicht in 64Bit-Ausführung. Da musst du deinen Kernel eh umschreiben (GDT, IDT, ...)
2. Kann man doch nicht für einen Treiber in den RM wechseln. Wo kommen wir da hin, dann könnte jeder Treiber die volle Macht übers System übernehmen.
3. Ich denke das BIOS ist bugfreier als der Code, den wir produzieren...
-
Ich würde generell vermeiden, den VM86 Mode zu nutzen, und ihn nur dann nutzen, wenn es unbedingt nötig ist (VESA Framebuffer z.B.). Er ist unportabel (x86_64 unterstützt ihn nicht mehr), switches zurück in den Realmode sind leichter, und das BIOS ist meistens auch nicht gerade bugfrei.
1. Wenn du nach Portabilität gehst, kannst du den PM vergessen, den gibt es auch nicht in 64Bit-Ausführung. Da musst du deinen Kernel eh umschreiben (GDT, IDT, ...)
2. Kann man doch nicht für einen Treiber in den RM wechseln. Wo kommen wir da hin, dann könnte jeder Treiber die volle Macht übers System übernehmen.
3. Ich denke das BIOS ist bugfreier als der Code, den wir produzieren...
Das sehe ich ganz genau so.
-
1. Naja, stimmt, wie der Kernel intern aufgebaut ist, ist egal. Und ob ich jetzt in den RM wechsele oder den VM86 Mode nutze ist dafür auch egal.
2. Ja, stimmt, das ist ein Vorteil des VM86 Modes. Allerdings ist der VM86 Mode auch nicht sehr sicher, ausser wenn du sehr viel emulierst. Du weißt z.B. nicht, auf welche Ports das Video-BIOS zugreifen muss, um VBE einzuschalten, daher musst du den Zugriff auf alle Ports erlauben, wodurch auch jeder Treiber die volle Macht übers System übernehmen könnte. (Über APM das System ausschalten usw.)
3. Naja, wenn in unserem Code Bugs sind, können wir sie beheben, beim BIOS müssen wir uns darauf verlassen, das alles klappt. Ausserdem will ich nicht alles vom BIOS machen lassen, sondern meine eigenen Treiber benutzen, ausser wenn es halt nicht möglich ist.
-
2. Ja, stimmt, das ist ein Vorteil des VM86 Modes. Allerdings ist der VM86 Mode auch nicht sehr sicher, ausser wenn du sehr viel emulierst. Du weißt z.B. nicht, auf welche Ports das Video-BIOS zugreifen muss, um VBE einzuschalten, daher musst du den Zugriff auf alle Ports erlauben, wodurch auch jeder Treiber die volle Macht übers System übernehmen könnte. (Über APM das System ausschalten usw.)
Das kannst du einfach herausfinden. Du sperrst alle Ports und lässt dir von den auftretenden Protected Faults zeigen, auf welche Ports zugegriffen wird. Die kannst du dann beim nächsten Durchlauf aufmachen, bis keine Faults mehr auftreten.
-
Die Ports, auf die zugegriffen wird können aber je nach System unterschiedlich sein.
-
2. Ja, stimmt, das ist ein Vorteil des VM86 Modes. Allerdings ist der VM86 Mode auch nicht sehr sicher, ausser wenn du sehr viel emulierst. Du weißt z.B. nicht, auf welche Ports das Video-BIOS zugreifen muss, um VBE einzuschalten, daher musst du den Zugriff auf alle Ports erlauben, wodurch auch jeder Treiber die volle Macht übers System übernehmen könnte. (Über APM das System ausschalten usw.)
Also meines Wissens nach haben Treiber in den meisten Betriebssystemen sowieso die volle Kontrolle über das System.
Das kannst du einfach herausfinden. Du sperrst alle Ports und lässt dir von den auftretenden Protected Faults zeigen, auf welche Ports zugegriffen wird. Die kannst du dann beim nächsten Durchlauf aufmachen, bis keine Faults mehr auftreten.
Wofür sollte man dann noch Ports sperre, wenn man sowieso alle Ports sofort wieder freigibt wenn sie benutzt werden?
-
2. Ja, stimmt, das ist ein Vorteil des VM86 Modes. Allerdings ist der VM86 Mode auch nicht sehr sicher, ausser wenn du sehr viel emulierst. Du weißt z.B. nicht, auf welche Ports das Video-BIOS zugreifen muss, um VBE einzuschalten, daher musst du den Zugriff auf alle Ports erlauben, wodurch auch jeder Treiber die volle Macht übers System übernehmen könnte. (Über APM das System ausschalten usw.)
Also meines Wissens nach haben Treiber in den meisten Betriebssystemen sowieso die volle Kontrolle über das System.
Ja, in Linux sowieso und in Windows haben es auch die meisten. Das ist aber kein Zeichen von einem gutem (möglichts stabilem) Kerneldesign (auch wenn es ein paar wenige % Performance bringt).
-
Ich habe oft gelesen, dass man DMA nicht benutzen sollte. Ich verstehe aber nicht warum. Hat das einen Nachteil? Geht das überhaupt ohne?
Das interessiert mich auch! Welches Register müsste man dann auslesen, um über P I/O an Daten zu kommen? 0x03F5?
-
Naja, DMA ist recht langsam (maximal 4MB/s) und kann nur die ersten 16 MB addressieren, er ist aber besser für Multitasking Umgebungen geeignet (wärend die Daten übertragen werden, kann die CPU was anderes machen.) und AFAIK kommt man beim FDC nicht um den DMA rum.
-
2. Ja, stimmt, das ist ein Vorteil des VM86 Modes. Allerdings ist der VM86 Mode auch nicht sehr sicher, ausser wenn du sehr viel emulierst. Du weißt z.B. nicht, auf welche Ports das Video-BIOS zugreifen muss, um VBE einzuschalten, daher musst du den Zugriff auf alle Ports erlauben, wodurch auch jeder Treiber die volle Macht übers System übernehmen könnte. (Über APM das System ausschalten usw.)
Also meines Wissens nach haben Treiber in den meisten Betriebssystemen sowieso die volle Kontrolle über das System.
Heißt nicht, dass wir so dumm sein müssen, und es auch machen. ;)
Das kannst du einfach herausfinden. Du sperrst alle Ports und lässt dir von den auftretenden Protected Faults zeigen, auf welche Ports zugegriffen wird. Die kannst du dann beim nächsten Durchlauf aufmachen, bis keine Faults mehr auftreten.
Wofür sollte man dann noch Ports sperre, wenn man sowieso alle Ports sofort wieder freigibt wenn sie benutzt werden?
Warum alle freigeben? Man gibt nur die frei, die gebraucht werden.
Die Ports, auf die zugegriffen wird können aber je nach System unterschiedlich sein.
Nein, FDC und DMA gehen immer über die gleichen Ports (zumindest bei x86), oder hast du schonmal was anderes gesehen? Und wenn: Wie soll man dann herausfinden, wo die sich verstecken?
-
Das bezog sich nicht auf DMA und FDC, sondern auf VBE.
-
Achso, ja, das kann sein. Aber wenn man VESA im RM mit LFB aktiviert, dann braucht man dafür eg. nichtmehr zurück in den RM.
-
Also ich komm da einfach nicht weiter. Ich habe alles mögliche versucht, aber nicht funktioniert. Das einzige was funktioniert ist: Motot an und Motor aus. Aber ich möchte jetzt aus testzwecken nur einen Sektor (Sektor 4, sprich den dritten Sektor) mit Daten beschreiben. Aber VMware zeigt mir eine Fehlermeldung an und Bochs macht gar nichts mehr. Der Sektor wurde auch nicht beschrieben. Was mache ich da falsch? Hier mein Code:
xor al,al
call fdc_activate_motor
mov bl,0Fh
call fdc_sendbyte
xor bl,bl
call fdc_sendbyte
xor bl,bl
call fdc_sendbyte
mov bl,01h
call fdc_wait
xor cl,cl
mov dx,07C0h
xor bx,bx
call dma_xfer ;bis hier mache ich glaube ich alles richtig
mov bl,0C5h ;jetzt komt der Fehler
call fdc_sendbyte
xor bl,bl
call fdc_sendbyte
xor bl,bl
call fdc_sendbyte
xor bl,bl
call fdc_sendbyte
mov bl,03h
call fdc_sendbyte
mov bl,02h
call fdc_sendbyte
mov bl,18
call fdc_sendbyte
mov bl,1Bh
call fdc_sendbyte
mov bl,0FFh
call fdc_sendbyte
xor bl,bl
call fdc_wait
jmp $
Hier mal die Funktionen von denen ich ausgehe das dort ein Fehler sein kann:
;input: bl, 0=ohne sensei, 1=mit sensei
;output: -
fdc_wait proc near
cmp irq6_done,1
jne fdc_wait
pusha
push bx
cli
mov cx,0007h
fdc_wait_loop:
mov dx,03F4h
in al,dx
and al,10h
or al,al
jz fdc_wait_weiter
dec cx
jz fdc_wait_weiter
call fdc_getbyte
jmp fdc_wait_loop
fdc_wait_weiter:
pop bx
or bl,bl
jz fdc_wait_no_sensei
mov bl,08h
call fdc_sendbyte
call fdc_getbyte
call fdc_getbyte
fdc_wait_no_sensei:
mov irq6_done,0
sti
popa
ret
fdc_wait endp
;input: bl = Byte das gesendet werden soll
;output: -
fdc_sendbyte proc near
pusha
mov cx,0080h
mov dx,03F4h
fdc_sendbyte_loop:
in al,dx
and al,0C0h
cmp al,80h
jne fdc_sendbyte_weiter
mov dx,03F5h
mov al,bl
out dx,al
popa
ret
fdc_sendbyte_weiter:
in al,80h
loop fdc_sendbyte_loop
popa
ret
fdc_sendbyte endp
;input: -
;output: bl = Byte aus dem Datenregister
fdc_getbyte proc near
push ax
push cx
push dx
mov cx,0080h
mov dx,03F4h
fdc_getbyte_loop:
in al,dx
and al,0D0h
cmp al,0D0h
jne fdc_getbyte_weiter
mov dx,03F5h
in al,dx
mov bl,al
pop dx
pop cx
pop ax
ret
fdc_getbyte_weiter:
in al,80h
loop fdc_getbyte_loop
pop dx
pop cx
pop ax
ret
fdc_getbyte endp
Es wäre wirklich nett wenn ihr euch das mal anschaut. Ich finde den Fehler einfach nicht.
Danke!!!
-
So, ich habe es nun entlich geschafft. Es funktioniert. Ich hatte das lesen/schreiben beim DMA Code vertauscht und den Kopf nicht zur richtigen Spur positioniert. Also wunderbar alles funktioniert. Aber jetzt habe ich immer noch ein kleines Problem. Was ist wenn jemand eine nicht 1,44 MByte Diskette mit meinem OS benutzen will? Würde es dann abstürtzen? Also im RM macht der int 13h das ja alles automatisch (außer natürlich die Anzahl der Heads, Sectors a Track usw.). Aber ich muss dem FDC genau die Formate angeben die er zu lesen hat. Also bitte ich um Informationen der verschiedenen Diskettenformate. Z.B. Wird bei 1,44 MByte als Länge der GAP3, 1Bh angegeben. Wie heißt es bei den anderen Formaten. Welche Datenrate brauchen die Formate? Wann kommt FM und wann MFM zu tragen? Also im Prinzip würde ich gerne alle Informationen über den Verschiedensten Diskettenformaten (natürlich nur die für den PC) haben. Danke!!!
bitmaster
-
@fdd_login(){
push cx
str cx
; Schon eingeloggt:
cmp [fdd_data_user],cx
jz .is_logged_in
cli ; Keine Interrupts, damit jetzt kein Taskwechesl kommt.
; Nein, ist das FDD frei:
cmp word ptr [fdd_data_user],0
jnz .error
mov [fdd_data_user],cx
sti
mov dword ptr [fdd_login_count],0
pop cx
mov cl,1
ret
.is_logged_in:
inc dword ptr [fdd_login_count]
pop cx
mov cl,1
ret
.error:
sti
pop cx
xor cl,cl
ret
}
Und was ist wenn genau nach dem jz .is_logged_in (bedingung nicht erfüllt) ein Taskwechsel stattfindet? Also das cli erst gar nicht ausgeführt wird?
bitmaster
-
MFM ist gültig bei High Density Disks, oder? Was macht das Bit7 beim schreib/lese Befehl? In einem Doku steht das dann die gewünschte Operation auf beiden Seiten ausgeführt wird. Aber es wird nicht von beiden Seiten gelesen/geschrieben obwohl ich das Bit7 gesetzt habe. Wäre auch irgendwie unlogisch. Aber wofür ist Bit7 denn dann wirklich?
bitmaster
-
Hallo,
wie gesagt funktioniert eigentlich alles. Nur habe ich festgestellt, dass es beim echten PC ziemlich langsam ist (das lesen und schreiben vom/auf Diskette). Also unter den Emulatoren läuft es ziemlich schnell bzw. normal. Aber wenn ich es auf einem wirklichen PC ohne Emulator laufen lasse, dauern 64 KByte lesen oder schreiben ca. 1,5 Minuten. Das ist viel zu lange. Auch hört man das Laufwerk kaum gegenüber das lesen im RM mit dem int 13h. Muss ich eigentlich bei jedem lesen/schreiben eines Sektors das Laufwerk rest(en)? Muss ich auch jedes mal die Drive-Timings setzten? Ich warte auch nirgendwo die 1/2 sekunden. Muss man das unbedingt? Warum und wo genau?
Danke!!!
bitmaster