Y2K - Sunteți pregătiți pentru anul 2000? Informațiile din memoria CMOSIon Gelu Tomșa Memoria de tip CMOS (Complementary Metal Oxide Semiconductor) cu capacitatea de 64 sau 128 octeți este de fapt o memorie de tip RAM, susținută de o baterie. La început această memorie era folosită ca o extensie de tip calendar-ceas pentru sistemele IBM-XT, iar la introducerea seriei PC-AT (Advanced Technology), în 1985, memoria CMOS a devenit o parte integrată a plăcii de bază. Întrucât ceasul și calendarul folosesc împreună numai 14 octeți RAM, restul octeților sunt disponibili pentru păstrarea principalelor informații de configurare a sistemului. Datorită existenței bateriei, conținutul acestei memorii se păstrează și după scoaterea de sub tensiune a calculatorului, permițând actualizarea ceasului-calendar și menținerea celorlalte informații.
Accesarea memoriei CMOSMemoria CMOS există în afara spațiului normal de adrese și nu poate conține cod direct executabil. Conținutul ei poate fi accesat prin comenzi IN și OUT trimise la porturile 70h (112) și 71h (113). Pentru a citi un octet din memoria CMOS, se trimite o comandă OUT portului 70h cu adresa octetului pe care dorim să-l obținem. Printr-o comandă IN la portul 71h se obține valoarea octetului cerut. Scrierea unui octet se face similar, printr-o comandă OUT la portul 70h cu adresa octetului pe care dorim să-l scriem, urmată de o comandă OUT la portul 71h cu valoarea octetului. Spațiul de memorie CMOS are o limită superioară de adresare de 128 octeți determinată de structura portului 70h: numai biții 0-6 sunt folosiți pentru adresare, iar bitul 7 este folosit pentru a activa (0) sau a dezactiva (1) întreruperile nemascabile (NMI). Din această cauză la scrierea/citirea octeților din această memorie adresa se obține efectuând operația: 80h OR <adresa>. Citirea unui octet din memoria CMOS se face astfel: a) în limbaj de asamblare: adr_octet db ? ; adresa din memoria CMOS val_octet db ? ; valoarea octetului mov AL, [adr_octet] out AL, 70h in AL, 71h mov [val_octet], AL b) în limbajul Turbo Pascal folosim tabloul predefinit port care permite accesul direct, la nivel de octet, la porturile calculatorului:
function citire_CMOS(adr_octet:Byte):Byte;
begin port[$70]:=adr_octet; citire_CMOS:=port[$71]
end;
c) în limbajul C apelăm funcțiile:
typedef unsigned char Byte; /* definim tipul Byte 0...255 */ Byte citire_CMOS(Byte adr_octet) { outportb(0x70, adr_octet); return(inportb(0x71)); }
Scrierea unui octet în memoria CMOS: a) în limbaj de asamblare:
mov AL, [adr_octet] out AL, 70h mov AL, [val_octet] out AL, 71h b) în limbajul Turbo Pascal: procedure scrie_CMOS(adr_octet,val_octet:Byte);
begin port[$70]:=adr_octet; port[$71]:=val_octet
end;
în limbajul C: void scrie_CMOS(Byte adr_octet,Byte val_octet) { outportb(0x70, adr_octet); outportb(0x71, val_octet); }
Observații: 1) Forma generală a instrucțiunilor IN, OUT (operațiile cu porturile în limbaj de asamblare) este: IN dest, port OUT dest, port în care dest este registrul AL sau AX, iar port este fie o constantă cuprinsă între 0 și 255, fie registrul DX. Semnificația instrucțiunilor este citirea, respectiv scrierea, de la portul de intrare/ieșire indicat, a unei valori pe un octet (8 biți) sau un cuvânt (16 biți). La procesoarele mai noi (începând cu 80286) regiștrii AL sau AX pot fi înlocuiți cu orice regiștri generali.
2) Funcțiile pentru lucrul cu porturile hardware în limbajul C au prototipurile în fișierul header dos.h:
unsigned char inportb(int port); void outportob(int port,unsigned char valoare);
3) Dacă memoria CMOS are disponibili numai 64 de octeți, adresele între 40h-7Fh vor oglindi exact conținutul din spațiul de adrese 00h-3Fh.
Organizarea memoriei CMOSCeasul sistem Adresele între 00h-0Eh sunt folosite pentru ceasul de timp real (RTC - Real Time Clock) și calendarul sistem și au aceeași semnificație pentru toți producătorii de Bios. Primii 14 octeți sunt folosiți pentru funcțiile cipului de ceas și constau din zece regiștri de scriere/citire date și patru regiștri de stare, dintre care doi regiștri permit operații de scriere/citire, iar ceilalți doi permit numai operații de citire. Datele sunt reprezentate, unde nu este specificat altfel, pe un octet. Datele reprezentate pe biți folosesc convenția de notare a biților: 0000 0000 7654 3210 cu bitul 7 cel mai semnificativ bit. Formatul celor zece regiștri de date (octeții 00h-09h) ai ceasului este următorul: CMOS 00h - RTC - SECUNDE Secunde ceas: zecimal 00-59, hexa 00-3B. CMOS 01h - RTC - SECUNDE ALARMĂ Secunde alarmă: zecimal 00-59, hexa 00-3B; nu are semnificație pentru valori între C0-FF CMOS 02h - RTC - MINUTE Minute ceas: zecimal 00-59, hexa 00-3B; nu are semnificație pentru valori între C0-FF CMOS 03h - RTC - MINUTE ALARMĂ Minute alarmă: zecimal 00-59, hexa 00-3B; nu are semnificație pentru valori între C0-FFh CMOS 04h - RTC - ORA Ore ceas: zecimal 00-23, hexa 00-17 dacă este modul cu 24 ore - zecimal 01-12, hexa 01-0C dacă este modul cu 12 ore am - zecimal 81-92, hexa 81-8C dacă este modul cu 12 ore pm CMOS 05h - RTC - ORA ALARMĂ Ore alarmă: la fel ca și la ore ceas CMOS 06h - RTC - ZIUA DIN SĂPTĂMÂNĂ Ziua din săptămână: 01-07 Duminică=1 CMOS 07h - RTC - DATA Data din lună: zecimal 01-31, hexa 01-1F CMOS 08h - RTC - LUNA Luna: zecimal 01-12, hexa 01-0C CMOS 09h - RTC - ANUL Ultimele două cifre ale anului 00-99, hexa 00-63 (vezi și CMOS 32h)
Observație Valorile sunt reprezentate în binar sau sunt codate BCD (cifre zecimale) iar selecția binar/BCD se face prin bitul 2 al registrului de stare B (0Bh); - selecția formatului cu 12/24 ore depinde de bitul 1 al registrului B (0Bh); - alarma se activează când toți cei trei regiștri folosiți de alarmă au valori egale cu cele ale regiștrilor de ceas corespunzători; alarma este accesibilă numai dacă bitul 5 al registrului B (0Bh) are valoarea 1.
Formatul regiștrilor de stare (octeții 0Ah-0Dh) este: CMOS 0A - RTC - REGISTRUL DE STARE A (citire/scriere) Descrierea biților pentru registrul de stare A este:
Bit Valoare Descriere 7 1 ciclu de actualizare a ceasului în execuție, ieșirile de date nedefinite 0 se poate face citirea (bitul 7 este Read only) 6-4 divizor cu 22 stadii 010 32768 Hz bază de timp (implicit) 3-0 biții pentru selectarea frecvenței de apel a întreruperii 0000 nici un apel 0011 122 microsecunde (minim) 1111 500 milisecunde 0110 976.562 microsecunde (implicit 1024 Hz) CMOS 0B - RTC - REGISTRUL DE STARE B (citire/scriere) Descrierea biților pentru registrul de stare B este:
Bit Valoare Descriere 7 1 permite ciclul de actualizare a ceasului 6 1 permite întreruperea periodică 5 1 permite înreruperea de alarmă 4 1 permite întreruperea cu actualizare la sfârșit 3 1 permite ieșirea square wave 2 1 modul de reprezentare a datelor 0: zecimal (BCD), 1: binar 1 1 selectare mod 24/12 ore: 1 selectează modul 24 ore 0 daylight savings enable
CMOS 0Ch - RTC - REGISTRUL DE STARE C (numai citire) Descrierea biților pentru registrul de stare C:
Bit(s) Descriere 7 Flag de cerere întrerupere, este egal cu 1 când oricare din biții 6-4 ai registrului B sunt setați cu valoarea 1. Generează IRQ 8 when triggered. 6 Flag întrerupere periodică 5 Flag întrerupere de alarmă 4 Flag întrerupere cu actualizare la sfârșit 3-0 Nefolosiți
CMOS 0Dh - RTC - REGISTRUL DE STARE D (numai citire) Descrierea biților pentru registrul de stare D:
Bit Descriere 7 Starea bateriei: 1 indică bateria în stare bună, 0 baterie descărcată sau deconectată 6-0 nefolosiți
Zona din memoria CMOS în afara ceasului sistemUrmătorii doi octeți, cu adresele 0Eh și 0Fh, nu sunt specificați pentru sistemele PC-AT dar pot avea pentru unele sisteme semnificația:
CMOS 0Eh - IBM PS/2 - octet de stare diagnostic Descrierea biților pentru octetul de stare în urma diagnosticului pentru sisteme IBM PS/2:
Bit Val. Descriere 7 1 indică întreruperea alimentării ceasului 6 1 sumă de control incorectă 5 1 eroare la lista de echipament: rutina POST nu a detectat toate echipamentele din listă 4 1 eroare la dimensiunea memoriei din cauză că rutina POST a determinat altă dimensiune a memoriei instalate 3 1 inițializare eșuată a controlerului sau unității de disc (harddisk defect); nu se poate încărca sistemul de operare de pe harddisk 2 1 oră invalidă 1 1 adaptorul instalat nu corespunde cu descrierea configurației 0 1 time-out în timpul citirii ID adaptorului
CMOS 0Fh - IBM - cod de reset (IBM PS/2 "Octet de stare la oprire")
Începând cu octetul 10h apare o descriere a perifericelor și informații de configurare: tipul unităților de floppy disk, hard disk, adaptor grafic, memorie instalată în sistem (de bază și extinsă), parola pentru accesul la informațiile de configurare (BIOS) sau accesul în sistem la pornire, parametrii memoriei cache, configurarea plăcii de bază, sloturi de extensie, parametrii pentru Power Management System (dacă sistemul permite economisirea energiei), asignarea întreruperilor hard, ș.a. Această zonă a memoriei CMOS nu este standardizată, producători diferiți dând interpretări diferite aceluiași octet. În continuare vom prezenta câteva din informațiile despre componentele instalate în sistem:
CMOS 10h - IBM - tip de unitate floppy Descrierea biților pentru tipul unităților floppy A/B:
Bit Descriere 7-4 tipul primei unități floppy (A:) 3-0 tipul celei de-a doua unități floppy (B:)
Valorile posibile pentru tipul unității floppy: 00h fără nici o unitate 01h Unitate de 360 KB 5.25" (depășită) 02h Unitate de 1.2 MB 5.25" 03h Unitate de 720 KB 3.5" 04h Unitate de 1.44 MB 3.5" 05h Unitate de 2.88 MB 3.5" 06h-0Fh nefolosiți???
Observație Pentru un calculator cu o singură unitate de 1.44MB acest octet are valoarea 0400h.
CMOS 11h-IBM PS/2 - tipul primului disk fix (00-FFh) CMOS 12h-IBM PS/2 - tipul celui de al doilea fix (00-FFh) CMOS 13h- rezervat CMOS 14h-IBM - octet descriere echipament
Bit Descriere 7-6 număr unități floppy - 1 00b - 1 unitate 01b - 2 unități 10b - 3 unități 11b - 4 unități 5-4 tip monitor 00b diferit de CGA sau MDA (folosit pentru EGA&VGA) 01b 40x25 CGA, EGA sau VGA 10b 80x25 CGA, EGA sau VGA 11b MDA (monocrom) 3 monitor instalat 2 tastatură instalată 1 coprocesor matematic instalat 0 unitate floppy instalată
CMOS 15h-IBM - memoria de bază în kb (octetul mai puțin semnificativ- low Byte) CMOS 16h-IBM - memoria de bază în kb (octetul semnificativ - high Byte )
Observație Valoarea octeților 15h-16h trebuie să fie aceeași cu valoarea păstrată în zona de date BIOS 0:413h și aceeași cu valoarea întoarsă de INT 12h. Pentru un PC având 640k (280h) de memorie convențională va apare valoarea 80h în octetul 15h și valoarea 02h în octetul 16h.
CMOS 17h-IBM - memoria extinsă în KB (octetul mai puțin semnificativ - low Byte) CMOS 18h-IBM - memoria extinsă în KB (octetul semnificativ - high Byte) Dimensiunea în KB a memoriei extinse (peste 1Mb) instalate. CMOS 1Bh-2DH rezervați CMOS 2Eh-IBM - Standard CMOS Checksum, High Byte CMOS 2Fh-IBM - Standard CMOS Checksum, Low Byte
Observație Octeții 2Eh și 2Fh sunt definiți pentru calculatorul original IBM PC-AT și se calculează numai pentru valorile locațiilor 10h-2Dh, valorile din domeniile de adrese 00-0Fh și 30h-3Fh nu sunt incluse. CMOS 30h - IBM - memoria extinsă în KB (low Byte) CMOS 31h - IBM - memoria extinsă în KB (high Byte)
Aceste valori sunt aceleași cu cele din octeții 17h-18h. CMOS 32h - IBM - secolul curent Acest octet reprezintă valoarea în format BCD pentru secol - în prezent 19. Actualizarea acestui octet determină compatibilitatea cu trecerea la anul 2000 a BIOS-ului. CMOS 33h-37h - octeți rezervați de producătorul CMOS: opțiuni pentru Setup, parola pentru AMI Bios - 38h-3Dh etc. CMOS 38h-3Fh - IBM-PS/2 - parola de activare Setup.
În aceste locații nu veți afla caracterele parolei ci se păstrează valoarea obținută prin aplicarea unei funcții de dispersie (hash) octeților din componența parolei; este posibil ca două (sau mai multe) parole diferite să fie acceptate ca fiind valide dacă au aceeași imagine prin funcția de dispersie. Scrierea de zerouri în octeții rezervați pentru parolă duce la anularea parolei. În unit-ul cmos.pas sunt scrise câteva proceduri/funcții folosite în programul test.pas care afișează informații despre configurația sistemului. Programul poate fi compilat-rulat și din mediul Borland Pascal pentru Windows dacă se folosește unit-ul wincrt în locul unit-ului crt.
Listing: CMOS.PAS unit CMOS;
interface uses crt; type timp=record ora,min,sec:Byte end; data=record secol,an,luna,data,ziua:Byte end; floppy=(none, D525_360, D525_12, D525_720, D35_144, D35_288); var fdd_A, fdd_B:Byte;
procedure GetTime(var T:timp); { citeste ora din ceasul sistem } procedure SetTime(var T:timp); { schimba ora din ceasul sistem } procedure ScrieOra; { afiseaza ora pe ecran } procedure GetData(var D:data); { citeste data din ceasul sistem } procedure SetData(D:data); { schimba data din ceasul sistem } procedure ScrieData; { afiseaza data pe ecran } procedure GetFddType(var fdd_A,fdd_B:Byte); { citeste tipul unitatilor de discheta } function NrFdd:Byte; { numarul unitatilor floppy instalate } function BaseMem:Word; { dimensiunea memoriei de baza } function ExtMem:Word; { dimensiunea memoriei extinse } implementation procedure BCD2bin(var b:Byte); { conversia din format BCD in format binar } begin b:=(b shr 4)*10+(b and $0f) end;
function bin2BCD(var b:Byte):Byte; { conversia din formatul binar in format BCD } begin bin2BCD:=(b div 10) shl 4+(b mod 10) end; procedure GetData(var D:data); var b:Byte; begin port[$70]:=$32; { RTC-secolul } D.secol:=port[$71]; BCD2bin(D.secol); port[$70]:=9;{ RTC-anul (ultimele 2 cifre) } D.an:=port[$71]; port[$70]:=8; { RTC-luna } D.luna:=port[$71]; port[$70]:=7; { RTC-ziua din luna } D.data:=port[$71]; port[$70]:=6; { RTC-ziua din saptamana } D.ziua:=port[$71]; port[$70]:=$0B;{ RTC-registrul de stare B } b:=port[$71]; if (b and 4)=0 then { format BCD } begin BCD2bin(D.an); BCD2bin(D.luna); BCD2bin(D.data); BCD2bin(D.ziua) end end;
procedure SetData(D:data); var b:Byte; begin port[$70]:=$0B;{ RTC-registrul de stare B } b:=port[$71]; port[$70]:=$0B; { format BCD } port[$71]:=b or 4; bin2BCD(D.secol); bin2BCD(D.an); bin2BCD(D.luna); bin2BCD(D.data); bin2BCD(D.ziua); port[$70]:=$32; { RTC-secolul } port[$71]:=D.secol; port[$70]:=9;{ RTC-anul (ultimele 2 cifre) } port[$71]:=D.an; port[$70]:=8; { RTC-luna } port[$71]:=D.luna; port[$70]:=7; { RTC-ziua din luna } port[$71]:=D.data; port[$70]:=6; { RTC - ziua din saptamana } port[$71]:=D.ziua end;
procedure GetTime(var T:timp); var b:Byte; begin port[$70]:=0; { RTC-secunde } T.sec:=port[$71]; port[$70]:=2; { RTC-minute } T.min:=port[$71]; port[$70]:=4; { RTC - ore } T.ora:=port[$71]; port[$70]:=$0B;{ RTC-registrul de stare B } b:=port[$71]; if (b and 2)=0 then { modul am/pm } if T.ora>12 then Dec (T.ora, $80+12); if (b and 4)=0 then { format BCD } begin BCD2bin(T.ora); BCD2bin(T.min); BCD2bin(T.sec) end end;
procedure SetTime(var T:timp); var b:Byte; begin port[$70]:=$0B;{ RTC-registrul de stare B } b:=port[$71]; port[$70]:=$0B; port[$71]:=(b or 4); bin2BCD(T.ora); bin2BCD(T.min); bin2BCD(T.sec); port[$70]:=0; { RTC-secunde } port[$71]:=T.sec; port[$70]:=2; { RTC-minute } port[$71]:=T.min; port[$70]:=4; { RTC-ore } port[$71]:=T.ora end;
procedure GetFddType(var fdd_A,fdd_B:Byte); var Tip:Byte; begin port[$70]:=$10; { RTC-Floppy drive type } Tip:=port[$71]; fdd_A:=Tip shr 4; fdd_B:=Tip and $0f end;
function NrFdd:Byte; var lista:Byte; begin port[$70]:=$14; lista:=port[$71]; if (lista and 1)=1 then NrFdd:=lista shr 6+1 else NrFdd:=0 end;
function BaseMem:Word; var l,h:Byte; begin port[$70]:=$15; { RTC-Base memory (low) } l:=port[$71]; port[$70]:=$16; { RTC-Base memory (high) } h:=port[$71]; BaseMem:=h shl 8+l end; function ExtMem:Word; var l,h:Byte; begin port[$70]:=$17;{ RTC-Extended memory (low) } l:=port[$71]; port[$70]:=$18;{ RTC-Extended memory (high) } h:=port[$71]; ExtMem:=h shl 8+l end;
procedure ScrieData; { afiseaza data pe ecran } var d:data; begin GetData(d); Write('Astazi este'); Write(D.data:2,'/',D.luna:2,'/',D.secol); if D.an<10 then Write('0'); Writeln(D.an); Writeln end;
procedure ScrieOra; { afiseaza ora pe ecran } var t:timp; begin GetTime(t); Write('Este ora: '); if t.ora<10 then Write('0',t.ora,':') else Write(t.ora,':'); if t.min<10 then Write('0',t.min,':') else Write(t.min,':'); if t.sec<10 then Write('0',t.sec) else Write(t.sec); Writeln end; End.
Listing: TEST.PAS program test; uses crt, cmos; procedure TipFdd; procedure Tip(f:Byte); begin case floppy(f) of none : Write('fără'); D525_360: Write('5.25"-360Kb'); D525_12 : Write('5.25"-1.2Mb'); D525_720: Write('5.25"-720Kb'); D35_144 : Write('3.5" - 1.44Mb'); D35_288 : Write('3.5" - 2.88Mb') end end; begin GetFddType(fdd_A,fdd_B); case NrFdd of 1: begin Write('Unitatea A: '); tip(fdd_A); Writeln end; 2: begin Write('Unitatea A: '); tip(fdd_A); Writeln; Write('Unitatea B: '); tip(fdd_B); Writeln end end end;
procedure ScrieMemBaza; begin Writeln('Memorie de baza: ',BaseMem,' Kb'); Write('Memorie extinsa: ',ExtMem,' Kb') end;
Begin Clrscr; Write('Astazi este: '); ScrieData; Write(' ora: '); ScrieOra; TipFdd; ScrieMemBaza; Readkey End.
Interfața Bios pentru ceasul de timp realOperațiile de citire/actualizare a zonei ceas/calendar sunt efectuate prin intermediul întreruperii BIOS 1ah care oferă accesul la ceasul de timp real (Real Time Clock) din memoria CMOS și la ceasul intern al sistemului. Acesta este actualizat de aproximativ 18.2 ori pe secundă (adică la un interval de 55ms). Funcțiile oferite de întreruperea 1ah sunt următoarele:
1) AH=00h Citirea ceasului sistem După apel: - regiștrii CX și DX conțin numărul de unități de timp de la pornirea calculatorului, CX octetul high și DX octetul low - registrul AL are valoarea 0 dacă nu au trecut 24 ore de la ultima punere la 0 a ceasului.
Observație Ceasul se actualizează de 1193180/65536 (aproximativ 18,2) ori pe secundă. Aceasta înseamnă: - 18 actualizări pe secundă - 1092 actualizări pe minut - 65543 actualizări pe oră - 1573040 actualizări pe zi. 2) AH=01h Scrierea ceasului sistem La apelul întreruperii regiștrii CX și DX conțin numărul de unități de timp de la pornirea calculatorului, CX octetul high și DX octetul low. 3) AH=02h Citirea orei din ceasul de timp real - CMOS După apel, în registrul CH se obține ora, în registrul CL minutul, iar în registrul DH secunda. Toate valorile sunt reprezentate în format BCD. 4) AH=03h Scrierea orei în ceasul de timp real - CMOS La apelul întreruperii registrul CH trebuie să conțină ora, registrul CL minutul și registrul DH secunda, toate în format BCD. 5) AH=04h Citirea datei din memoria CMOS După apel în registrul CH se obține secolul, în registrul CL anul, în registrul DH luna și în registrul DL data, toate valorile reprezentate în format BCD. 6) AH=05h Scrierea datei în memoria CMOS La apel registrul CH conține secolul, CL conține anul, DH conține luna și DL conține data în format BCD. 7) AH=06h Stabilirea orei pentru alarma ceasului de timp realCeasul de timp real oferă posibilitatea activării unei întreruperi de tipul 4ah la o oră fixată prin apelul acestei funcții (întrerupere de alarmă). La apelul acestei funcții registrul CH trebuie să conțină ora, registrul CL minutul, registrul DH secunda, toate în reprezentare BCD. Întreruperea 4ah este activată când apare egalitatea între valorile corespunzătoare ceasului sistem și alarmei din memoria CMOS. Implicit rutina de tratare a acestei întreruperi conține doar o instrucțiune de revenire din întrerupere (IRET), dar poate fi înlocuită cu o rutină scrisă de utilizator. Această întrerupere este disponibilă numai pentru sisteme cu microprocesor 80286 sau mai bun. 8) AH=07h Anularea ultimei alarme stabilite Această funcție permite anularea unei alarme înainte de stabilirea altei alarme.
Observație La un moment dat poate fi stabilită o singură alarmă. Pentru a schimba ora alarmei trebuie anulată eventual ultima alarmă. Aceste funcții sunt implementate în unit-ul rtc.pas prezentat mai jos.
Listing: Unit-ul RTC {$F+} unit rtc; interface uses dos; type data=record secol,an,luna,data:Byte end; timp=record ora,min,sec:Byte end;
function GetTicks:LongInt; procedure SetTicks(t:LongInt); procedure ReadTime(var t:timp); procedure SetTime(t:timp); procedure ReadDate(var d:data); procedure SetDate(d:data); procedure SetAlarm(t:timp); procedure ResetAlarm;
implementation var r:registers;
function BCD2bin(b:Byte):Byte; { conversia BCD binar } begin BCD2bin:=(b shr 4)*10+(b and $0F) end;
function bin2BCD(var b:Byte):Byte; { conversia din formatul binar in format BCD } begin bin2BCD:=(b div 10) shl 4+(b mod 10) end;
function GetTicks:LongInt; { citeste nr. } { de unitati de timp de la ultima resetare } begin r.AH:=0; intr($1a,r); GetTicks:=r.CX shl 16 + r.DX end;
procedure SetTicks(t:LongInt); { seteaza nr. } { de unitati de timp de la ultima resetare } begin r.AH:=01; r.CX:=t shr 16; r.DX:=(t shl 16) shr 16; intr($1a,r) end;
procedure ReadTime; { citeste ora } begin r.AH:=02; intr($1a,r); t.ora:=BCD2bin(r.CH); t.min:=BCD2bin(r.CL); t.sec:=BCD2bin(r.DH) end;
procedure SetTime; { seteaza ora } begin r.AH:=03; r.CH:=bin2BCD(t.ora); r.CL:=bin2BCD(t.min); r.DH:=bin2BCD(t.sec); intr($1a,r) end;
procedure ReadDate; { citeste data } begin r.AH:=04; intr($1a,r); d.secol:=BCD2bin(r.CH); d.an:=BCD2bin(r.CL); d.luna:=BCD2bin(r.DH); d.data:=BCD2bin(r.dl) end; procedure SetDate; { seteaza data } begin r.AH:=05; r.CH:=bin2BCD(d.secol); r.CL:=bin2BCD(d.an); r.DH:=bin2BCD(d.luna); r.dl:=bin2BCD(d.data); intr($1a,r) end;
procedure SetAlarm; { seteaza alarma } begin r.AH:=06; r.CH:=bin2BCD(t.ora); r.CL:=bin2BCD(t.min); r.DH:=bin2BCD(t.sec); intr($1a,r) end;
procedure ResetAlarm; { anulare alarma } begin r.AH:=07; intr($1a,r) end; End.
Problema compatibilității cu anul 2000Problema compatibilității Bios-ului cu anul 2000 înseamnă schimbarea corectă a datei odată cu schimbarea datei sistemului la schimbarea anului și mileniului din 31 decembrie 1999 la 1 ianuarie 2000 și recunoașterea și raportarea corectă a datei după anul 2000 (până în anul 2099!). Compatibilitatea la nivel Bios cu această problemă înseamnă recunoașterea corectă a datei numai de către sistem și nu garantează funcționarea sigură a programelor care folosesc date calendaristice (programe de gestiune, aplicații bancare, sisteme de control). Aplicațiile care folosesc date calendaristice trebuie testate și certificate separat pentru compatibilitatea cu această problemă (year 2000 bug) ceea ce duce la un volum imens de aplicații care trebuie modificate/certificate într-un timp relativ scurt. Testarea Bios-ului pentru compatibilitate cu anul 2000 se poate face foarte simplu prin intermediul funcțiilor oferite de întreruperea 1ah. Pentru aceasta se salvează data și ora curentă și se schimbă data la 31 decembrie 1999, ora 23:59:55. Urmărind ceasul puteți afla dacă trecerea la anul nou 2000 este făcută cu actualizarea corectă a datei. Programul care testează schimbarea datei în BIOS este prezentat mai jos. Pentru AwardBios după data apariției se poate determina dacă este compatibil cu trecerea la anul 2000 astfel: a) Dacă BIOS-ul are data producerii înainte de 26 aprilie 1994, trebuie să resetați ceasul sistem o singură dată astfel: 1. opriți calculatorul înainte de miezul nopții pe 31 decembrie 1999; 2. porniți-l cândva după miezul nopții, pe 1 ianuarie 2000; 3. scrieți apoi data corectă în Setup. b) Dacă BIOS-ul a fost produs între 26 aprilie 1994 și 31 mai 1995 trebuie să obțineți un Bios actualizat de la firma producătoare sau să resetați ceasul sistem zilnic! c) Dacă BIOS-ul a fost produs după 31 mai 1995, calendarul face automat trecerea de la anul 1999 la anul 2000 la miezul nopții. Nu mai trebuie să faceți nimic, indiferent dacă sistemul este pornit sau oprit la miezul nopții. Pentru detalii suplimentare pot fi utile și referințele următoare: www.phoenix.com www.unicore.com
Listing: Y2K.PAS program anul2000; uses crt, rtc; const anul_nou:data =(secol:19;an:99;luna:12;data:31); ora_12:timp=(ora:23;min:59;sec:55); var azi, D:data; T:timp; i:Integer;
procedure HideCursor; assembler; { ascunde cursorul de pe ecran } asm mov AX, $0100 mov CX, $2607 int $10 end;
procedure ShowCursor; assembler; { arata cursorul pe ecran } asm mov AX, $0100 mov CX, $0506 int $10 end;
procedure ScrieData; { afiseaza data } var d:data; begin ReadDate(d); with d do begin if data<10 then Write('0'); Write(data,'/'); if luna<10 then Write('0'); Write(luna,'/',secol); if an<10 then Write('0'); Write(an) end end;
procedure ScrieOra; { afiseaza ora } var t:timp; begin ReadTime(t); with t do begin if ora<10 then Write('0'); Write(ora,':'); if min<10 then Write('0'); Write(min,':'); if sec<10 then Write('0'); Write(sec)
end end;
Begin HideCursor; TextBackGround(black); Clrscr; TextColor(yellow); GotoXY(2,25); Write('-= Program 2000 v. 1.0 - (c)'); Write(' 1999 Tomsa Ion-Gelu =-'); TextColor(cyan); GotoXY(1,3); Write(' Acest program testeaza daca '); Writeln('Bios-ul calculatorului dvs.'); Write('actualizeaza corect data la '); Writeln('trecerea in anul 2000.'); TextColor(magenta); Write('Apasati orice tasta pentru a '); Writeln('incepe testarea...'); TextColor(cyan); ReadKey; Write('Memorez data si ora curenta: '); ScrieData; Writeln(' ora '); ScrieOra; ReadDate(azi); ReadTime(T); Write('Schimb data si ora: '); SetDate(anul_nou); SetTime(ora_12); i:=0; TextColor(white); GotoXY(wherex,wherey-1); while i<10 do begin GotoXY(21,WhereY+1); ScrieData; Write(' ora '); ScrieOra; Delay(1000); Inc(i) end; Writeln; ReadDate(d); if d.secol=20
then Writeln('Actualizare corecta a datei BIOS !')
else begin Write('Bios-ul calculatorului dvs. nu '); Writeln('este compatibil cu anul 2000...'); end; TextColor(cyan); Write('Refac data si ora: '); SetDate(azi); Inc(t.sec,10); if t.sec>59
then
begin Inc(t.min); Dec(t.sec,60) end; SetTime(t); ScrieData; Writeln(' ora '); ScrieOra; TextColor(magenta); Writeln('Apasati orice tasta'); Readkey; ClrScr; TextColor(cyan); Write('Program: '); TextColor(yellow); Writeln('2000 v.1.0(c)1999 Tomsa Ion-Gelu'); TextColor(cyan); Write('Autor :'); TextColor(LightBlue); Writeln('Tomsa Ion Gelu'); TextColor(Cyan); Write('e-mail:'); TextColor(Red); Writeln('tom@cnamd.ubbcluj.ro'); Delay(5000); ShowCursor End.
Bibliografie:1. Vlad Căprariu, Andrei Enyedi, Marius Muntean, Marius Chiorean - Sistemul de operare DOS. Ghidul programatorului, Editura MicroInformatica, Cluj-Napoca 1991; 2. Tech Help!, manual electronic hipertext.
Domnul Tomșa Ion Gelu este profesor de informatică la Colegiul Național "Andrei Mureșanu", Dej. Poate fi contactat prin e-mail la adresa: tom@cnamd.ubbcluj.ro [cuprins] |