repeat
prikaz1;
prikaz2;
.
.
.
prikazN;
until keypressed;
Pokud bude tento kus kódu detailně rozebírat někdo, kdo nemá ani
ponětí o přerušovacím systému, vytanou mu (možná) na mysli tyto
otázky:INT 10h
,
na němž je pověšen prográmek, který mé požadavky vykoná.
Další často používaná služba je INT 21h
, která obsahuje funkce
DOSu (práce se soubory, vstup/výstup řetězce, spouštění příkazového řádku...).
Výhodou tohoto použití je, že pokud nám nějaká takováto služba nevyhovuje
či ji chceme rozšířit, není problém si na obsluhu přerušení napojit svůj
program.
keep
, jejímž parametrem
je pouze návratový kód, který program předá DOSu (tzv. ERRORLEVEL). Ten
sice většinou k ničemu není, ale neboť Pascal neumožňuje proměnný počet parametrů,
musíte tam stejně něco napsat (nejlépe kód 0="program skončil bez chyby").
Pouhé volání této procedury je však k ničemu - v paměti sice zůstane viset kód, ale
protože ho nemá kdo nebo co spustit, je v počítači platný asi jako XT-čko v bytě pařana.
Musíme tedy zařídit, aby byl program při určité konkrétní události v systému spuštěn -
a, jak již víme, události systému spracovávají právě přerušení. Je tedy třeba z určité
části našeho rezidentního programu udělat obsluhu přerušení (samozřejmě je
možno udělat i více obsluh více přerušení).INT 0
, pak následuje
INT 1
atd. až poslední INT 255
. Každé z těchto přerušení
má svůj úkol (přesněji řečeno většina z nich, některá jsou nepoužitá). Například INT 8
se
generuje každých 55milisekund vnitřními hodinami počítače, INT 9
při stisku klávesnice
atd. atd., zbytek si jistě vyhledáte sami. Změnu a čtení této tabulky uskutečníme pomocí procedur SetIntVec(cisloPreruseni:byte;AdresaProcedury:pointer)
GetIntVec(cisloPreruseni:byte;var AdresaProcedury:pointer)
. {$F+}
. FAR znamená, že budou volány za pomocí plné čtyřbajtové
adresy tj. volatelné odkudkoli z operační paměti (podrobnější vysvětlení by bylo na delší povídání).
interrupt
těsně za hlavičkou.
INT 8
.
const CISLO=...;
var stara_obsluha:procedure;
procedure nova_obsluha;forward;
procedure prohod_vektory; {volá se z hlavního programu}
begin
getintvec(CISLO,@stara_obsluha);
setintvec(CISLO,@nova_obsluha);
end;
procedure nova_obsluha;interrupt;
begin
......
asm pushf end;
stara_obsluha;
......
end;
Assemblerovská instrukce PUSHF se musí před voláním uvést.
Důvod je malinko složitější, následující odstavec s vysvětlením proto,
jestli chcete, můžete přeskočit:
var jehoSS,jehoSP,mujSS,mujSP:word;
procedure nova_obsluha;interrupt;
begin
asm
cli
mov jehoSS,SS
mov jehoSP,SP
mov SP,mujSP
mov SS,jehoSP
sti
end;
...... {vlastní tělo obsluhy}
asm
cli
mov SS,jehoSS
mov SP,jehoSP
sti
end;
end;
To je celkem pochopitelné - prostě na začátku nahradíme jeho hodnoty svými a na konci
ty jeho zase vrátíme (...toto je obecná filozofie zacházení se systémovými zdroji, obvzláště
se musí striktně dodržovat v rezidentním programu, pokud si nechceme pobourat systém).
Hodnoty mujSS, mujSP
zjistíme na začátku, tedy v hlavním programu:
begin {hlavní program}
asm
cli
mov mujss,SS
mov mujsp,SP
sti
end;
..........
end.
Instrukce CLI zabezpečuje, že během provádění dalších akcích neproběhnou přerušení, které by
akce mohly porušit, dokud přerušení zase nepovolím instrukcí STI.
{$D-,Q-,R-,S-}
uses dos;
{$M $400,0,0}
{$F+}
var
old09:procedure; {stará obsluha přerušení}
mujss,mujsp:word; {..registry ukazující na můj zásobník}
jehoss,jehosp:word; {..tyto ukazují na zásobník přerušeného programu}
procedure new09;interrupt;
const count:byte=0;
var scan,s:byte;i:word;
begin
asm pushf end;
old09; {<--tímto volám starou obsluhu přerušení}
asm
cli
mov jehoss,SS
mov jehosp,SP
mov SS,mujss
mov SP,mujsp
sti
end;
{JÁDRO OBSLUHY PŘERUŠENÍ}
s:=scan;
scan:=port[$60];
if scan in [10..50] then begin
if scan<>s then
case scan of
32:if count=0 then inc(count);
30:if count=1 then inc(count);
49:if count=2 then inc(count);
else count:=0;
end;{case}
if count=3 then begin
for i:=1 to 3000 do port[$61]:=port[$61] or (i mod 4); {různé zapínej/vypínej reprák}
port[$61]:=port[$61] and (not 3);{nosound}
count:=0;
end;{count3}
end;{scan v 10 az 50}
{TADY KONČÍ JÁDRO OBSLUHY}
asm
cli
mov SS,jehoss
mov SP,jehosp
sti
end;
end;{proc New09}
{$F-}
begin
asm {schovám hodnoty zásobníku}
cli
mov mujss,SS
mov mujsp,SP
sti
end;
getintvec(9,@old09); {prohodím vektory přerušení}
setintvec(9,@new09);
keep(0); {skonči a zůstaň rezidentní}
end.
Ještě byste mohli namítnout, proč jsem ten rezident nenapsal tak, aby
se dovedl odinstalovat. Podle mého názoru je to však zbytečné, neboť
Volkov Commander má jednu skvělou vlastnost, že pokud byly po jeho natažení
instalovány nějaké rezidentní programy, sám je při svém ukončení nebo i
explicitně na váš příkaz umí odinstalovat.
Rezidentní programy se také samy uvolňují, pokud byly spuštěny z Wokenního
DOS-PROMPTu.
Toť vše. Rezidentní programy mají spoustu použití, tak zkuste nějaké vymyslet!
This page was created using notepad.exe and my brain |