MASM lemezszektor olvasó lapozható tartalommal

Előkép

A következő program beolvas egy (Floppy)lemezről egy (512 byte-os) szektort. Lényegében egy házi feladat volt az egyetemen, hogy csinosítsuk ki keretekkel, esetleg menükkel a programot, ami már előre meg volt írva. Ezen célon túllőve nem csak a kimenetet csinosítottam, hanem a forráskódot is. Jóllehet, túl is bonyolítottam.

Az igazsághoz hozzá tartozik, hogy a program csak floppy lemezről tud beolvasni. 3 féle megoldást próbáltam ki a lemezszektor olvasásra, de némi utánajárás után kiderült, hogy vagy az oprendszer nem támogatja a módszert, vagy a fájlrendszer. Nem beszélve arról, hogy egy virtuális FAT12 -es merevlemezt sem tudtam olvasni, tehát maradt konkrétan a virtuális floppy csatolás virtualboxban egy virtuális XP-vel. Floppy képet egyébként készen is lehet letölteni a neten.



Adatbekérés

Kiírás

Erre azért volt szükség, mert nincs már a gépemben floppy meghajtó. Hozzáteszem az egyetemen sincs azon a gépen, ahol be kellett mutatni a programot. Így persze senki nem tudta élesben bemutatni, csak aki laptop-ot vitt, és a fent leírt virtuális módszert használva saját gépén bírta működésre a lemezolvasót. Nekünk, többieknek maradt az "ignore" gomb nyomogatása, amikor a windows felszólított, hogy nincs mit olvasni. Így a memóriából valami szemetet kiírva a képernyőre lett bemutatva a program.

De nézzük akkor a programot, ami letölthető a következő linken is: Letöltés

.model small

.stack

.data    
    hexaPosX = 5
    posY = 3
    charRelPosX = 5
    rows = 15
   
    ;-------------------------
    hexaWidth = 47 ;3*16-1, mert az utolso hexa utan nem kell space
    charWidth = 16
    borderWidth = hexaWidth+charRelPosX+charWidth+2
    charPosX = hexaPosX+hexaWidth+charRelPosX
    ;------------------------------
    ESCAPE = 27
    cr = 13     ;carrige return (kocsi vissza)
    lf = 10     ;line feed (uj sor)
    space = ' '
   
    maxRows = 512 / 16
    lastPageRows = maxRows mod rows
    maxPage = (maxRows / rows) + ((lastPageRows+(rows-1)) / rows )
   
    dcrlf db cr,lf,0   ;uj sor
    goodbye db 'Szep napot! Hasznalj maskor is!!',0
    goodbyeLength = $-goodbye-1
    borderTop db 201, hexaWidth + (charRelPosX/2) dup(205), 203,
                      (charRelPosX/2) + charWidth dup(205), 187,0
    borderMiddle db 186
    borderBottom db 200, hexaWidth + (charRelPosX/2) dup(205) ,202,
                     (charRelPosX/2) + charWidth dup(205) , 188,0
    pagenum db 0
    offs dw 0
   
    txtPage db 'Oldal: ',0
    txtDiskId db 'Lemez:',0
    txtBlockNumber db 'Block szama:',0
   
    quit db 0
   
.data?
    block db 512 dup(?)
.code

writem_char macro chr    ;atadott karakter kiirasa kepernyore
    push dx
   
    mov dl, chr
    call write_char
   
    pop dx
endm

writem macro string       ;atadott karakter kiirasa kepernyore
    push bx
   
    lea bx, string
    call write_string
   
    pop bx
endm

gotoXY macro x, y       ;kurzor pozicionalasa x, y pozicioba (x=oszlop, y=sor)
    push dx             ;hasznalt regiszterek mentese
    push ax
    push bx

    mov dh, y           ;dh-ba kell kerulnie az sorszamnak
    mov dl, x           ;es dl-be kell kerulni a oszlopszamnak
    mov ah, 2h          ;A kettes kod a kurzor pozicionalasa

    xor bh, bh          ;Hasznalt kepernyo lap szama 0
    int 10h             ;képernyő driver hivasa

    pop bx              ;regiszterek visszatoltese
    pop ax
    pop dx
endm

gotoXYRel macro x, y
    push dx             ;hasznalt regiszterek mentese
    push ax
    push bx
    push cx

    mov ah, 03h
    xor bh, bh
    int 10h

    add dh, y           ;dh-ba kell kerulnie az sorszamnak
    add dl, x           ;es dl-be kell kerulni a oszlopszamnak
    mov ah, 2h          ;A kettes kod a kurzor pozicionalasa

    xor bh, bh          ;Hasznalt kepernyo lap szama 0
    int 10h             ;képernyő driver hivasa

    pop cx
    pop bx              ;regiszterek visszatoltese
    pop ax
    pop dx
endm

writeto macro string, x, y ;szoveg kiirasa x, y pozicioba
    gotoxy x, y            ;eloszor pozicionalas
    writem string          ;majd kiiras
endm

read_char proc uses ax  ;egy karakter beolvasasa
    mov ah, 1           ;karakter bekeres kodja
    int 21h             ;hexa 21 -es megszakitas DOS-funkciok hivasahoz
                        ;A karakter ekkor AL regiszterbe kerül
    mov dl, al          ;A karakter-t a DL regiszterbe tesszuk
    ret                 ;visszateres subrutinbol
read_char endp

;dl-ben levo kezdocimtol string kiirasa
write_string proc uses bx dx
    .while byte ptr [bx] != 0
      mov dl, [bx]
      call write_char
      inc bx
    .endw
    ret
write_string endp

;dl-ben varja mit kell kiirni
write_char proc uses ax
    mov ah, 2h  ; Kiiras kodja
    int 21h
    ret
write_char endp

;adatszegmens inicializalasa
dsinit proc uses ax  
    mov ax, dgroup   ;adatszegmens kezdocime ax-be
    mov ds, ax       ;ezt betoltjuk az adatszegmens regiszterbe
    ret
dsinit endp

;DOS kepernyo torlese
clrscr proc uses ax
    mov ax, 3  ;3-as bekerul ah-ba. Utasitas kepernyo torlesere
    int 10h    ;hexa 10-es megszakitas. Kepernyo driver hivasara
    ret
clrscr endp

;sortores
linebreak proc
    writem dcrlf
    ret
linebreak endp

lcase proc
    .if (dl >= "A" && dl <= "Z")
        add dl, "a"-"A"
    .endif
    ret
lcase endp

read_block proc uses ax bx cx dx

    writeto txtDiskId, 26, 6
    writeto txtBlockNumber, 20, 7
   
    gotoXY 33, 6
    call read_char
    .if dl == ESCAPE
        mov quit, 1
        ret
    .endif
    call lcase
    sub dl, 'a'
    mov al, dl

    gotoXY 33, 7
    call read_decimal

    lea bx, block
    mov cx, 1 ;beolvasando blokkok száma  
    int 25h
    popf
    ret
read_block endp

out_line_hexa proc uses bx cx dx
    mov cx, 16
    .repeat
        mov dl, block[bx]
        call write_hexa
        mov dl, space
        call write_char
        inc bx
    .untilcxz
    ret
out_line_hexa endp

out_line_char proc uses bx cx dx
    mov cx, 16
    .repeat
        mov dl, block[bx]
        .if dl < space
            mov dl, space
        .endif
        call write_char
        inc bx
    .untilcxz
    ret
out_line_char endp

init_write_block proc
    .if pagenum == (maxPage-1) && lastPageRows
        mov cx, lastPageRows
    .else
        mov cx, rows
    .endif
    add bx, offs
    ret
init_write_block endp

write_block_hexa proc uses cx bx
    call init_write_block
    .repeat
        gotoXYRel hexaPosX, 0
        call out_line_hexa
        call linebreak
        add bx, 16
    .untilcxz  
    ret
write_block_hexa endp

write_block_char proc uses cx bx
    call init_write_block
    .repeat
        gotoXYRel charPosX, 0
        call out_line_char
        call linebreak
        add bx, 16
    .untilcxz  
    ret
write_block_char endp

write_hexa_digit proc uses dx
    .if dl >= 10
        add dl, 'A'-'0'-10
    .endif
    add dl, '0'        
    call write_char
    ret
write_hexa_digit endp

write_hexa proc uses cx dx
    mov dh, dl
    mov cl, 4
    shr dl, cl
    call write_hexa_digit
    mov dl, dh
    and dl, 0Fh
    call write_hexa_digit

    ret
write_hexa endp

read_decimal proc uses ax bx
    mov bx, 10
    xor ax, ax
    xor dx, dx
   
    .while 1
        call read_char
        .break .if dl == cr
        sub dl, '0'
        mul bl
        add ax, dx
    .endw
    mov dx, ax
    ret
read_decimal endp

write_decimal proc uses ax dx cx si
    mov ax, dx
    mov si, 10   ; 10-el osztjuk si-t

    xor cx, cx   ; cx torlese

    .while ax != 0
        xor dx, dx
        div si
        push dx
        inc cx
    .endw

    .repeat
        pop dx
        call write_hexa_digit
    .untilcxz
    ret
write_decimal endp

readCmdKey proc
    mov ah, 00h
    int 16h
    ret
readCmdKey endp

pager proc uses dx ax
    .if al == 0
      .if (ah == 'H' && pagenum >= 1)
         dec pagenum
      .elseif (ah == 'P' && pagenum < (maxPage-1))
         inc pagenum
      .endif
       mov ax, rows*16
       mul word ptr pagenum
       mov offs, ax
    .endif  
    ret
pager endp

hideCursor proc uses ax cx dx bx
    mov ah, 03h
    int 10h
    or ch, 30h
    mov ah, 1
    int 10h
    ret
hideCursor endp

goodbyeProc proc uses ax
    call clrscr
    call hideCursor
    mov al, goodByelength
    shr al, 1
    mov ah, 40
    sub ah, al
    gotoXY ah, 12
    writem goodbye
    ret
goodbyeProc endp

writeInfo proc uses dx bx

    ;oldal info
    writem txtPage
    xor dx, dx
    mov dl, maxPage
    call write_decimal
    writem_char '/'
    ;oldalszam
    mov dl, pagenum
    inc dl
    call write_decimal
    ret
writeInfo endp

drawBorder proc uses cx ax
    ;felso keret
    gotoXY hexaPosX-1, posY-1
    writem borderTop
    ;kozepso resz
    mov cx, rows
    mov al, posY
    .repeat
       gotoXY hexaPosX-1,al
       writem_char borderMiddle
       gotoXY hexaPosX+hexaWidth+(charRelPosX/2), al
       writem_char borderMiddle
       gotoXY hexaPosX+borderWidth-2, al
       writem_char borderMiddle
       inc al
    .untilcxz
    ;keret alja
    gotoXY hexaPosX-1, al
    writem borderBottom
    inc al
    ;keret alatti informacios sav
    gotoXY hexaPosX, al
    call writeInfo
   
    gotoXY 0, 0
    ret
drawBorder endp

run_read_block proc uses ax
    call read_block
    .if quit == 1
        ret
    .endif
    mov pagenum, 0
    .repeat
        call clrscr
        call hideCursor
        call drawBorder
        gotoXYRel 0, posY
        call write_block_hexa
        .if pagenum == (maxPage-1) && lastPageRows
            gotoXYRel 0, -lastPageRows
        .else
            gotoXYRel 0, -rows
        .endif
        call write_block_char                                  
        call readCmdKey
        call pager
        gotoXY 0, 0
    .until al == ESCAPE
   ret
run_read_block endp

main proc
    call dsinit
    call clrscr
    call hideCursor
   
    ;comment *
    .repeat
    .break .if quit == 1
        call clrscr
        call run_read_block
    .until al == ESCAPE
    call goodbyeProc
    call readCmdKey
    ;*
   
    .exit
main endp

end main

Most túl sokat nem kommentálnám. A forráskódban sem hagytam sok megjegyzést. Akit érdekel, kipróbálhatja. Meg persze kérdezni lehet. De nem hiszem, hogy sokan ütik el a drága idejüket assembly forráskódok tanulmányozásával :)

A programban a szektor megjelenítésnél le és fel nyilakkal lehet lapozni. ESC -re kilép a lemez betűjel és szektor szám ( hányadik szektor ) bekéréshez. Újabb ESC-re pedig kilép a programból. Persze előbb illedelmesen elköszön.

Kategóriák: 
Megosztás/Mentés