Tak bychom mohli ten program už konečně dodělat a spustit.
Programu už schází jen ta vlastní prováděcí část. Ve zdrojovém textu máme komentář, že „zde bude program pokračovat…“. Tak do tohoto místa vložíme novou část, která je obarvena červeně, celý zdrojový text zde vypisován nebude, jen jeho část:
ld de,16384+128+10 ;nastav pozici tisku
ld hl,T_HOTOVO ;text
call PRINT ;vytiskni
ld a,(VYSLEDEK) ;vezmi vysledek
ld l,a
ld h,0
call NUM2DEC ;a vytiskni
ld a,'%'
call ZNAK2 ;a za nim znak %
call READ_DISK ;nacti 14 sektoru z diskety
call FIND_FILE ;najdi soubor run.P
jr nz,NEXT_DISK ;nenalezen, dalsi disk
ld (HEADER),hl ;uloz si adresu hlavicky
call UPRAVA ;pokus se jej modifikovat
NEXT_DISK:
ld ix,DISKETA
call BCDE_IX ;ukazatel na disketu
ld ix,(AKTPAR) ;ukazatel na udaje o partition
ld a,16 ;NEXTDISK
call SERVICE
jr c,RETURN ;HOTOVO, dalsi disketa neni
Je vidět, že budeme potřebovat rutinu, která nám načte FAT a DIR diskety, rutinku, která soubor run.P najde, rutinu, která nám jej upraví a opravené sektory uloží zpět.
Takže postupně. Rutina na načtení sektorů je jednoduchá, nepotřebujeme dodržet pořadí souborů, takže 14 sektorů načteme jednoduchou smyčkou:
READ_DISK:
ld a,14 ;14 sektoru
ld hl,DIR
ld ix,DISKETA ;nacti udaje do BCDE
call BCDE_IX
/ push af ;uloz pocitadlo
ld a,10 ;INC32
call SERVICE ;BCDE+1
push bc ;ulozi
push de
jp z,ERROR ;pokud prelezlo na 0 je nekde ERROR
ld a,25 ;READHDD
call SERVICE ;nacti
inc c
dec c ;je-li chyba-skoncime
jp nz,ERROR ;jinak hl=hl+512
pop de
pop bc ;obnov LBA
pop af ;obnov pocitadlo sektoru
dec a
jr nz,- ;opakuj 14x
ret
Tak. Co tam máme dál? Najití souboru. Banalitka, je to opsáno z „rutiny ROM D40“:
FIND_FILE: ld hl,DIR+3072 ;zacatek adresare
ld de,32 ;delka jedne polozky
ld b,128 ;pocet polozek
/ push bc ;vsecko schov
push de
push hl
ld b,11 ;jedenact znaku
ld de,PRUN
call COMPARE ;porovnej
pop hl
pop de
pop bc
ret z ;nalezen, pak HL=adresa polozky
add hl,de ;posun adresu na dalsi polozku
djnz -
ld a,e ;shozeni zero flagu
or a
ret
PRUN: db "Prun"
db 0,0,0,0,0,0,0
Následuje vlastní úprava. Jde o to, že máme soubor run.P, musíme najít ty správné sektory, najít v nich ty správné hodnoty podle verze File Manageru, patchnout a uložit zpět. Původně jsem chtěl dělat nějaký univerzální program, ale rozmyslel jsem si to. Jestli to někdo chce, nechť si jej udělá za domácí úkol.
Úprava provede načtení 6. a 7. sektoru souboru run.P, čísla těchto sektorů si uloží a při zpětném uložení na disk toho využijeme. Jednotlivé verze FM se liší takto:
1.07 a 1.08 mají na offsetu 472 hodnotu 145 a na 475 hodnotu 153
1.10 má na offsetu 548 hodnotu 145 a na 551 pak hodnotu 153.
Přepočítané ale na sektory 6 a 7. Patch to zkontroluje a patchne. Nakonec se sektory, pokud byly nějak opraveny, uloží, čísla sektorů jsou zapamatována.
UPRAVA:
ld ix,(HEADER)
ld l,(ix+17)
ld h,(ix+18) ;cislo prvniho sektoru
ld b,6
/ call FDBLOCK ;zjisti nasledujici sektor
ld hl,3072
sbc hl,de ;je prazdny?
ret z
ld a,d ;posledni sektor
cp 14
ret nc ;ano
ex de,hl
djnz - ;
;tedka: HL = cislo 6 sektoru souboru run.P
push hl
ld ix,SECTOR1
call LBA
pop hl
call FDBLOCK
ld a,d
cp 14 ;jestli je precasny konec
ret nc ;neni to spravny soubor
ex de,hl
ld ix,SECTOR2 ;takze uz zname LBA sektory
call LBA ;nasich dvou sektoru
call LOAD_2LBA ;takze je nacti
call PATCH ;oprav data
ret nz ;data nebyla opravena
ld a,2
out (254),a ;cerveny bordel
call SAVE_2LBA ;uloz zpet
xor a ;cerny bordel
out (254),a
ret
PATCH:
ld hl,DATA+471
ld de,OUT145
ld b,2
call COMPARE
jr nz,FM110
ld hl,DATA+474
ld de,OUT153
ld b,2
call COMPARE
jr nz,FM110 ;FM 1.07 to neni
ld hl,DATA+472
ld (hl),151
ld hl,DATA+475
ld (hl),155
jr PATCH_RET
FM110: ld hl,DATA+547
ld de,OUT145
ld b,2
call COMPARE
ret nz
ld hl,DATA+550
ld de,OUT153
ld b,2
call COMPARE
ret nz ;FM 1.10 to neni
ld hl,DATA+548
ld (hl),151
ld hl,DATA+551
ld (hl),155
PATCH_RET: xor a
ret
OUT145: db 211,145
OUT153: db 211,153
LBA: push ix
ld ix,DISKETA
call BCDE_IX
inc hl ;musime se posunout na bootsektor
ld a,12 ;ADD32HL
call SERVICE ;pricti HL k BCDE
jp c,ERROR ;jakasi chyba, ktera by nemela nastat
pop ix
jp IX_BCDE ;uloz LBA na sve misto
LOAD_2LBA: ld ix,SECTOR1
ld hl,DATA
call LOAD
ld ix,SECTOR2
LOAD: call BCDE_IX ;nacti jej do BCDE
ld a,25
call SERVICE ;nalouduj
inc c
dec c ;nejaka chyba?
jp nz,ERROR
ret
SAVE_2LBA: ld ix,SECTOR1
ld hl,DATA
call SAVE
ld ix,SECTOR2
SAVE: call BCDE_IX ;nacti jej do BCDE
ld a,26
call SERVICE ;sejvni
inc c
dec c ;nejaka chyba?
jp nz,ERROR
ret
Mezi proměnnými přibyly nové položky:
HEADER: dw 0 SECTOR1: dw 0,0 SECTOR2: dw 0,0
a v pracovním prostoru ještě místo na další data:
DIR: ds 14*512 DATA: ds 2*512
Celý hotový program je ke stažení, zkoušel jsem jej na svých datech a pracoval dobře.
V celém programu jsme si vyzkoušeli hodně služeb MDOS3, jako bylo zjištění adresy AKTPAR a její význam, příkazy NEXTDISK a ADD1693 taky nejsou nezajímavé, stejně tak pracují služby PREVDISK a DEC1693. Načtení a uložení sektoru je taktéž důležité a to vše bez toho, abychom se starali, jestli disk podporuje LBA nebo ne, prostě LBA používáme. Jsou k dispozici další podpůrné službičky, využili jsme INC32 tuším.
stažení:
3 komentáre na “Programujeme pro MDOS3 (4)”
Je nám líto, ale formulář pro přidávání komentářů je momentálně uzavřen.
I napriek tomu, ze je to velmi dobre a pekne napisane, neodpustim si pripomienky podobneho razu ako v druhom pokracovani "serialu".
Rovnako ako na konci v minule spomenutej rutine COMPARE je nepotrebna instrukcia ‚xor a‘, tak aj v rutine FIND_FILE su na konci zbytocne instrukcie ‚ld a,e‘ a ‚or a‘, kedze instrukcia ‚add hl,de‘ neovplyvnuje Zero flag a instrukcia ‚djnz xyz‘ neovplyvnuje ziadne flagy. Teda po neuspesnom hladani NEBUDE Zero priznak nastaveny, co sa od tejto rutiny ocakava.
Tak isto je navestie PATCH_RET zbytocne a aj prislusna instrukcia ‚xor a‘, pretoze v tomto mieste je vdaka vysledku rutiny COMPARE a nasledujucim instrukciam, ktore flagy nemenia, priznak Zero uz nastaveny.
Tak snad ma neukamenujete… 🙂
Ahoj Romane. Děkuji ti za tvoje připomínky. A to myslím vážně, protože jsem nepředpokládal, že by snad někdo ten zdroják až takhle studoval. Velice mě to těší.
Ještě dodatek: chyby jsem tam nechal, laskavý čtenář si je případně opraví sám a může si zkusit třeba i něco navíc. Mě osobně by třeba zajímalo, jak by se laskavý čtenář vypořádal s problémem výběru jiného oddílu.
Nuž, keďže to nemám ako vyskúšať a overiť, tak môžem iba teoreticky zauvažovať 🙂
Rutinu GET_AKTPAR a jej volanie by som nahradil rutinou napr. GET_NEXTPART, ktorá by postupne prechádzala tabuľkou PART_TABLE a pripravila adresu ďalšieho oddielu z tabuľky (preskakovala by oddiely 252 a 253). Zaroveň by na tomto mieste začínala dalšia vonkajšia slučka, ktora by vlastne prechádzala cez všetky nájdené oddiely. Samozrejme, pred tým musí byť pomocou služby 4 pripravená počiatočná adresa PART_TABLE pre rutinu GET_NEXTPART.
V časti, kde sa pomocou služby 16 hľadá ďalší disk na aktuálnom oddieli a pri neúspechu skáče na návesie RETURN, by sa skočilo na začiatok novej slučky. Na navestie RETURN by sa skočilo, ak by rutina GET_NEXTPART prešla cez všetky oddiely.
Teda, prešli by sa všetky "platné" oddiely bez ohľadu na práve vybraný.
Tak to bola moja teoretická úvaha, snáď správna a zrozumiteľná …. 🙂