Много кто знает, что на материнской плате компьютера находится микросхема, постоянно считающая время, называемая часами реального времени, системным таймером или КМОП - микросхема (КМОП - комплементарная структура металл — оксид — полупроводник), работает она от батарейки, расположенной на материнской плате.
На самом деле, эта интегральная схема служит не только для отсчёта времени, а ещё хранит пароль в зашифрованном виде, способствует генерации звуковых сигналов, хранит в себе информацию о конфигурации компьютера, контрольную сумму ячеек памяти, определяет из - за чего отключается компьютер, используя число, соответствующее варианту отключения.
У КМОП - микросхемы есть своя область памяти, номер ячейки памяти и её содержимое приведены ниже:
00h - 05h Используются часами реального времени
06h - 09h Дата и день недели в BCD
0Ah - 0Dh Регистры A, B, C, D
0Eh Байт состояния диагностики при
включении питания
0Fh Байт состояния отключения
10h Тип используемого НГМД
11h Зарезервировано
12h Тип НМД (если тип меньше 15)
13h Зарезервировано
14h Конфигурация оборудования
15h - 16h Объем основной памяти
17h - 18h Объем расширенной (extended) памяти
19h Тип первого НМД (если тип > 15)
1Ah Тип второго НМД (если тип > 15)
1Bh - 20h Зарезервировано
21h - 2Dh Зарезервировано
2Eh - 2Fh Контрольная сумма ячеек 10h - 20h
30h - 31h Объем расширенной (extended) памяти
32h Текущее столетие в двоично-десятичном
коде (19h для 19-го столетия)
33h Различная информация
34h - 3Fh Зарезервировано
Чтение из этой памяти осуществляется при помощи двух операций:
1. Необходимо записать номер нужной ячейки памяти в порт 70h
2. Из порта 71h прочитать содержимое ячейки
Пример:
Код: Выделить всё
mov al, 14h ;номер ячейки памяти, в которой записан байт конфигурации оборудования
out 70h, al ;записываем число в порт 70h
in al, 71h ;чтение байта из ячейки памяти
У системного таймера имеется несколько режимов работы, программируется таймер с помощью записи битов в порты 43h и 40h (системный таймер имеет несколько программируемых каналов, это порты каналов 0 и 2, канал 1 не используется в программах, трогать его не советую, этот канал отвечает за регенерацию памяти, в документации информации о нём нет).
Формат управляющего слова для программирования каналов системного таймера:
биты
-7-6----5-4----3-2-1----0
-|-|----|-|----|-|-|----|
Канал---Вид----Режим---Счёт
------операции---------0 - Двоичный
-----------------------1 - BCD
Коды режимов работы кварцевого генератора:
0 - формирование одиночного прямоугольного сигнала заданной длительности
1 - формирование одиночного сигнала заданной длительности с аппаратным запуском
2 - генерация кратковременных периодических сигналов
3 - генерация периодических прямоугольных сигналов со скважностью 2 (меандр)
4 - формирование кратковременного сигнала с заданной задержкой
5 - формирование кратковременного сигнала с заданной задержкой с аппаратным запуском
Коды вида операций чтения - записи каналов таймера:
0 - чтение "на лету"
1 - чтение-запись младшего байта области памяти канала
2 - чтение-запись старшего байта области памяти канала
3 - чтение-запись сначала младшего, затем старшего байта области памяти канала
Изменение частоты прерываний системного таймера:
Код: Выделить всё
.model tiny
.286
code segment
org 100h
start:
mov al, 36h ;канал 0, режим 3, вид операции 3
out 43h, al ;управляющее слово в порт
mov ax, 6535d ;число - константа для установки частоты 182 Гц
out 40h, al ;младший байт в область памяти канала таймера
mov al, ah ;AL = старший байт константы
out 40h, al ;старший байт в область памяти канала таймера
mov ax, 4c00h
int 21h
code ends
end start
Теперь давайте выведем на экран информацию о конфигурации компьютера, читая из памяти системного таймера эти значения:
Код: Выделить всё
.model tiny
.286
code segment
org 100h
start:
mov cx, s_rtc
mov si, offset cmos.rtc
;read rtc_area
mov di, offset con_out.nums1+1
rtc_area:
mov al, byte ptr[si]
out port_out, al
in al, port_in
call hex_ascii
add di, 3d
inc si
loop rtc_area
;read diagnoctic byte
mov al, cmos.diag
out port_out, al
in al, port_in
mov di, offset con_out.d_diag+18
call hex_ascii
;read shutdown byte
mov al, cmos.shut
out port_out, al
in al, port_in
mov di, offset con_out.d_shut+18
call hex_ascii
;read reserved bytes
mov cx, s_res
mov di, offset con_out.nums2+1
mov si, offset cmos.res
read_res:
mov al, byte ptr[si]
out port_out, al
in al, port_in
call hex_ascii
add di, 3d
inc si
loop read_res
;read checksum
mov cx, s_check
mov si, offset cmos.check
mov di, offset con_out.nums3+1
read_check:
mov al, byte ptr[si]
out port_out, al
in al, port_in
call hex_ascii
add di, 2d
inc si
loop read_check
;read extended memory
mov cx, s_ex_ram
mov si, offset cmos.ex_ram
mov di, offset con_out.nums4+2
read_ex_ram:
mov al, byte ptr[si]
out port_out, al
in al, port_in
call hex_asciid
add di, 3d
inc si
loop read_ex_ram
;display values
mov ah, 9d
mov dx, offset con_out
int 21h
mov ax, 4c00h
int 21h
hex_asciid proc uses dx cx bx di ax
xor ah, ah
mov bx, 0Ah
xor dx, dx
calculate:
cmp al, 0
jz exp
div bx
add dl, 30h
mov byte ptr[di], dl
dec di
xor dx, dx
jmp calculate
exp:
ret
hex_asciid endp
;DI - offset of last byte in memory
;AL - number
hex_ascii proc uses di cx bx
mov cx, 2d
write:
mov bl, al
and bl, 0Fh
cmp bl, 9d
ja letter
add bl, 30h
mov byte ptr[di], bl
dec di
shr al, 4d
loop write
jmp exitp
letter:
add bl, 37h
mov byte ptr[di], bl
dec di
shr al, 4d
loop write
exitp:
ret
hex_ascii endp
cmos_ struc
rtc db 0, 1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d, 9d, 0Ah, 0Bh, 0Dh
diag db 0Eh
shut db 0Fh
res db 1Bh, 1Ch, 1Dh, 1Eh, 1Fh, 20h
check db 2Eh, 2Fh
ex_ram db 30h, 31h
cmos_ ends
cmos cmos_ <>
s_rtc equ sizeof cmos.rtc
s_res equ sizeof cmos.res
s_check equ sizeof cmos.check
s_ex_ram equ sizeof cmos.ex_ram
port_in equ 71h
port_out equ 70h
con_out_ struc
d_rtc db 'Real Time Clock:', 9d
nums1 db 2d dup(0), 20h, 2d dup(0), 20h, 2d dup(0), 20h, 2d dup(0), 20h
db 2d dup(0), 20h, 2d dup(0), 20h, 2d dup(0), 20h, 2d dup(0), 20h, 2d dup(0)
db 20h, 2d dup(0), 20h, 2d dup(0), 20h, 2d dup(0), 20h, 2d dup(0), 0Ah, 0Dh
d_diag db 'Diagnostic byte:', 9d, 2d dup(0), 0Ah, 0Dh
d_shut db 'Shutdown byte: ', 9d, 2d dup(0), 0Ah, 0Dh
d_res db 'Reserved: ', 9d
nums2 db 2d dup(0), 20h, 2d dup(0), 20h, 2d dup(0)
db 20h, 2d dup(0), 20h, 2d dup(0), 20h, 2d dup(0), 0Ah, 0Dh
d_check db 'Checksum: ', 9d
nums3 db 2d dup(0), 2d dup(0), 0Ah, 0Dh
d_ex_ram db 'Extended ram: ', 9d
nums4 db 4d dup(20h), 30h, 0, 20h, 'Kbytes', 24h
con_out_ ends
con_out con_out_ <>
code ends
end start
Все программы написаны на версии компилятора MASM 6.11 в контексте операционной системы MS DOS 6.22!
Спасибо за внимание!
С уважением, push0ret.