www.agora.ro

Y2K - Sunteți pregătiți pentru anul 2000?

Informațiile din memoria CMOS

Ion 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 CMOS

Memoria 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 CMOS

Ceasul 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 sistem

Urmă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 real

Operaț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 real

Ceasul 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 2000

Problema 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.ami.com www.award.com

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]