МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ "ЛЬВІВСЬКА ПОЛІТЕХНІКА"
Кафедра САПР
ГРАФІЧНО-РОЗРАХУНКОВА РОБОТА
З курсу : 
«Системне програмування»
(Варіант 14)
ЛЬВІВ – 2015
	                       Робота з годинником реального часу.
Сучасні комп’ютери оснащено двома підсистемами таймерів, які паралельно відраховують поточний час. Один таймер розміщено у мікросхемі з низьким споживання енергії (КМОП-мікросхема), яка після вимкнення живлення комп’ютера продовжує працювати, отримуючи енергію від вбудованого у комп’ютер аккумулятора (батареї). Цей таймер, як правило, називають годинником реального часу (RTC); окрім кварцевого генератора і систем керування він має внутрішню пам’ять, у якій зберігається й постійно нарощується значення поточного часу. Оновлення часу здійснюється щосекунди, причому ця операція виконується на апаратному рівні, не задіюючи в даному процесі ні процесор, ні оперативну пам’ять.
                                         Підсистема ГРЧ
Підсистема ГРЧ включає в себе контролер та невеликий блок пам’яті об’ємом 64 байт. Перші 14 байт використовються для відліку часу; решта 50 байт зберігають інформацію про конфігурацію системи. Підсистема забезпечує наступні функції:
відлік поточного часу з точністю до 1 с;
роботу будильника, який у встановлений час генерує сигнал переривання лінією IRQ8, закріпленним за вектором 70h;
режим періодичних переривань (лінією IRQ8), частоту яких можна програмно налаштовувати у межах від 2 Гц до 8 КГц;
зберігання даних про конфігурацію системи (об’єм базової та розширеної пам’яті, типи магнітних дисків і т.д.);
зберігання даних прикладних програм.
У таблиці  наведено призначення окремих байтів КМОП-пам’яті (0-3Fh).
                                   Адресний простір пам’яті КМОП-мікросхеми
Адреса
поля
Кількість байт
Призначення
1
2
3
00h
1
Секунди в BCD
01h
1
Секунди будильника в BCD
02h
1
Хвилини в BCD
03h
1
Хвилини будильника в BCD
04h
1
Години в BCD
05h
1
Години будильника в BCD
06h
1
День тижня (може бути відсутній)
07h
1
Число в BCD
1
2
3
08h
1
Місяць (січень – 1, лютий – 2 і т.д.) в BCD
09h
1
Рік, молодші дві цифри в BCD
0Ah
1
Регістр A
0Bh
1
Регістр В
0Ch
1
Регістр С
0Dh
1
Регістр D
0Eh
1
Байт діагностування
0Fh
1
Байт кода скиду процесора
10h
1
Типи HDD (якщо менше 15)
11h
1
Зарезервовано
12h
1
Типи дискет
13h
1
Зарезервовано
14h
1
Склад встановленого обладнання
15h
2
Об’єм базової пам’яті, Кбайт
17h
2
Об’єм розширеної пам’яті, Кбайт
19h, 1Ah
2
Тип першого HDD (якщо більше 15)
1Bh
14
Зарезервовано
2Eh
2
Контрольна сума байтів 10h-2Dh
30h
2
Об’єм розширеної пам’яті, Кбайт
32h
1
Рік, перші дві цифри в BCD
33h
1
Системна інформація
34h
12
Зарезервовано
Байти з номерами 0Ah, 0Bh, 0Ch та 0Dh виконують функції керуючих регістрів. 
0Ah – регістр стану RTC:
    7    6    5   4    3    2    1   0
 
                                                       
 
                                                    0-3: швидкість відліку
                                                    4-6: дільник
                                                    7: прапор оновлення
0Bh – регістр стану RTC:
   7    6   5    4    3    2   1    0
 
                                                   
 
                                                    0: тип часу
                                                    1: 12- або 24-годинний формат часу
                                                         
                                                    2: формат даних: 0=BCD,
                                                        1=двійковий;
                                                    3: 1=дозволити прямокутний імпульс
                                                        
                                                    4: 1=дозволити переривання від
                                                        кінця оновлення
                                                    5: 1=дозволити переривання
                                                        будильника (сигнальне переривання)
                                                    6: 1= дозволити періодичне
                                                         переривання 
                                                    7: прапор оновлення
0Ch – регістр стану RTC: біти стану переривання (тільки чатання).
0Dh – регістр стану RTC. Біт D7=1, якщо CMOS отримує живлення від автономного джерела; 0 – відсунє живлення від автононого джерела.
0Eh – байт байт результатів початкового тестування.
  7   6    5   4    3    2    1   0
                                    0   0          
 
                                                2: 1= формат поточного часу
                                                    
                                                3: 1=HDD не завантажується
                                                    
                                                4: 1=розмір ОЗП неправильний
                                                5: 1=пристрій не відповідає
                                                    конфігурації CMOS
                                                6: 1=неправильна контрольна сума CMOS
                                                7: 1=не працює автономне джерело живлення 
                                                    CMOS
0Fh – байт стану перезавантаження. Цей байт зчитується після скиду ЦП, щоб визначити, чи не було скиду, викликаного виведенням 80286 з захищеного режима. Він може мати наступні значення:
0	–	гарячий рестарт (Ctrl-Alt-Del) або неочікувана зупинка;
1	–	зупинка після визначення розміру ОЗП;
2	–	зупинка після тестування пам’яті;
3	–	зупинка після виявлення помилки паритета пам’яті;
4	–	рестарт за запитом початкового завантажувача;
5	–	рестарт за скидом контролера переривань та JMP FAR PTR [0:467h];
6, 7, 8 – зупинка після теста захищеного режиму;
9	–	рестарт за JMP FAR PTR [0:467h].
Звертання до байтів КМОП-пам’яті здійснюється за допомогою портів 70h та 71h у два етапи: спочатку в порт 70h записується номер необхідного байта пам’яті; потім через порт 71h виконується читання (in) чи запис (out) байта пам’яті.
Наприклад, прочитаємо та виведемо на екран поточний рік. На лістингу 3.1 наведено вихідний текст програми.
 Програма читаня з RTC інформації про об’єм розширеної пам’яті
#include <stdio.h>
#include <dos.h>
int main (void)
{
	unsigned char XMS_H,XMS_L;
	int XMS;
	outportb(0x70,0x17);
	XMS_L=inportb(0x71);
	outportb(0x70,0x18);
	XMS_H=inportb(0x71);
	XMS=XMS_H;
	XMS=XMS>>8;
	XMS+=XMS_L;
	printf("Об’єм розширеної пам’яті = %dKb",XMS+1024);
	return 0;
}
Після виконання програми 2-байтна змінна XMS матиме значення на 1024 менше, ніж повний об’єм  пам’яті (у Кбайтах), встановленої на комп’ютері. Аналогічно можна отримати, наприклад, об’єм базової пам’яті (байти 15h та 16h).
Описаним вище способом можна звертатись до всіх чарунок CMOS-пам’яті, за винятком перших десяти. Справа в тому, що КМОП-мікросхема один раз за секунду виконує корекцію поточного часу та перевірку стану будильника. На час корекції ділянка КМОП-пам’яті, яка відноситься до годин, календаря та будильника, відключається від системної магістралі та стає недоступним для програмного звертання. На це й же час встановлюється біт D7 регістра А. Тому перед зверненням до адрес 00h-09h CMOS-пам’яті необхідно спочатку дочекатись скиду біта D7 регістра А, що вказує на завершення процесу корекції і тільки потім здійснювати зверення до пам’яті. В лістингах 3.2-3.3 продемонстровано читання чарунок КМОП-пам’яті з очікуванням закінчення цикла корекції.
 Програма читання з RTC та виведення на екран поточного року
#include <stdio.h>
#include <dos.h>
int main (void)
{
	unsigned char YearH, YearL;
	do{
		outportb(0x70,0x0A);
	}while ((inportb(0x71)&0x80)==1);  //біт D7 рег. А 
                                       // встановлено?
	outportb(0x70,0x32);  //байт 32h - старші 2 цифри року
	YearH=inportb(0x71);	
	outportb(0x70,0x09);  //байт 9h - молодші 2 цифри року
	YearL=inportb(0x71);
	printf("Поточний рiк: %02x%02x",YearH,YearL);
	return 0;
}
Лістинг 3.3 – Програма читання з RTC та виведення на екран поточної дати
#include <stdio.h>
#include <dos.h>
int main (void)
{
	unsigned char Day, Mon;
	do{
		outportb(0x70,0x0A);
	}while ((inportb(0x71)&0x80)==1); //корекцію завершено (D7 Ah)?
	outportb(0x70,0x07);	//07 – число в ВСD (з табл. 3.1)
	Day=inportb(0x71);
	outportb(0x70,0x08);	//08 – місяць в ВСD (з табл. 3.1)
	Mon=inportb(0x71);
	printf("Поточна дата: %02x.%02x",Day,Mon);
	return 0;
}
ГРЧ працює від внутрішнього кварцового генератора, частоту якого підібрано таким чином, щоб сигнали на його виході (після перерахунку) мають частоту точно 1 Гц (щосекунди). Ці сигнали використовуються для відліку поточного часу в байтах годин та календаря КМОП-пам’яті. Окрім постійного перерахунку, який забезпечує частоту 1 Г, в КМОП-схему включено ще вузол настроюваного перерахунку, вихідні сигнали якого поступають на лінію IRQ8, ініціалізуючи перілдичні переривання через вектор 70h. Коефіцієнт перерахунку і, відповідно, частоту періодичних переривань можна програмного налаштовувати, змінюючи біти D0-D3 регістра А. Для дозволу/заборони періодичних переривань використовується біт D6 регістра В.
Встановлення будильника здійснюється записом необхідного часу розбудження в байти секунд, хвилин та годин КМОП-пам’яті (див. таблицю 3.1). Під час запису в ці чарунки необхідно передбачити очікування кінця циклів корекції, як це показано у лістингу 3.2. Схеми таймера періодично порівнюють поточний час з часом, який записаний у байтах будильника, і при досягненні рівності збуджує сигнал сигнального переривання на лінії IRQ8. Для дозволу/заборони сигнальних переривань необхідно ініціалізувати біт D5 регістра В.
Якщо відповідні значення встановлено у всіх трьох байтах будильника, сигнальні переривання буде формуватись у вказаний час щодоби. Проте програмно можна встановити в одном або декількох байтах будильника “довільний” код – будь-яке число від C0h до FFh. 
Якщо довільний код встановлено у байті годин будильника, то сигнальні переривання збуджуються щогодини. Після запису довільного кода у байт годин та хвилин – сигнал генерується щохвилини, а за наявності довільного коду у всіх трьох чарунках – щосекунди.Особливість цього режима заключається в тому, що переривання формуються не просто заданої частоти, а у заданий момент кожної хвилини або кожної години. Наприклад, якщо у байті сукунди записано число 30h, а в байтах хвилин та годин – C0h, то переривання будуть збуджуватись точно на 30-й секунді кожної хвилини.
При обробці переивань від CMOS-мікросхеми необхідно враховувати, що сигнали, призначені для збудження переривань (сигнальних та періодичних), поступають на вхід контролера переивань не безпосередньо, а через розряд D7 регістра С, який виконує функції прапора переривань. Програма обробки переривань повинна скинути прапор переривання, інакше подальші надходження сигналів переривань будуть заблокованими. Скид прапора переривань здійснюється шляхом читання регістру С.
Для читання та зміни показників RTC передбачено переривання BIOS 1Ah, функції якого звертаються безпосереньо до КМОП-пам’яті і дозволяють не тільки отримати чи встановити час та дату, але й керувати будильником.
Основні функції переривання BIOS 1Ah:
00h – отримання системного часу;
01h – встановлення системного часу;
02h – отримання часу від CMOS-годинника реального часу;
03h – встановлення часу у CMOS-годиннику реального часу;
04h – отримання дати від CMOS-календаря реального часу;
05h – встановлення дати у CMOS-календаря реального часу;
06h – встановлення будильника у CMOS-годиннику реального часу;
07h – відміна будильника у CMOS-годиннику реального часу.
Є ще переривання 4Ah, яке служить для перехоплення прикладною програмою сигнала від будильника RTC. INT 4Ah включено у системний обробник переривання 70h  від будильника в RTC. Системний обробник цього переривання фактично виконує лиш команду IRET; прикладна програма може встановити власний обробник переривання 4Ah, який буде активізуватись сигналом будильника.
Як видно з таблиці 3.1, адреси СMOS 10h-2Dh захищено контрольною сумою, яка зберігається за адресою 2Eh. Тому зміна вмісту даних чарунок пам’яті необхідно супроводжувати зміною і контрольної суми.
Порт 70h використовується не тільки для індексування адреси CMOS-чарунки, але й для дозволу/заборони NMI (немасковане переривання). Якщо біт D7 скинуто, то NMI дозволено, якщо втсановлено – NMI заборонено.
             Задача  1
Написати з використанням циклів і оформити згідно вимог програму на асемблері для рисування вказаним кольором прямокутника заданого розміру у місці екрану, заданому координатами лівої верхньої вершини за допомогою мишки.
Ширина - 75
Висота - 45
Колір – 5
Текст програми: 
title   first
sseg    segment stack
        db      256 dup(?)
sseg    ends
dseg    segment
pc	  dw	?    
dseg    ends
cseg    segment
        assume  ss:sseg,cs:cseg,ds:dseg
start:  jmp main
main:   push   ds
        mov    ax,0
        push   ax
        mov    ax,dseg
        push   ax 
        mov    ax,12h
        int    10h
        mov    ax,0
        int    33h
p:      mov    ax,1
        int    33h
d:      mov    ax,3
        int    33h
        test   bx,10b
        jnz    ex
        test   bx,1b
        jz d
        mov ax,2
        int 33h
	  mov si, cx
  mov pc, si
  add     si,75
  dec     si
  mov		di, dx
  add     di,45
	  dec     di
	  mov al,5 
	  mov bh,0
        mov ah,0ch
		
c1:	  mov cx, pc
c:	  int 10h
	  inc cx
	  cmp	cx,si
	  jle	c
	  inc	dx
	  cmp dx,di
	  jle	c1
ex:     mov ax,4c00h
        int 21h 
cseg    ends
        end start
/
Задача  2
З використанням функції DOS  написати програму для роботи з файлами та каталогами створити каталог (прізвище студента) , перейти в створений каталог, створити і відкрити файл ( ім’я студента ), записати й файл текст (ім’я батька), закрити файл і перейти в кореневий каталог.
sseg		segment        stack     		 ; опис стеку
		db	   	256 dup (?)
sseg		ends
 ;------------------------------------------------------------
dseg	 	segment                        		; опис даних
newcat		db		'\Lutsyshyn',0
newfile 	db              'Ihor',0
rootcat 	db      	'c:\',0
poch		db		'Vvedit imja batka: $'
buf db  15 dup(?)
c			db		0
error		db		'error$'
dseg		ends	
 ;-----------------------------------------------------------
cseg	segment				; типовий початок програми
	assume	cs:cseg, ds:dseg, ss:sseg
start:	jmp	main
main:	push	ds
	mov	ax,0
	push	ax
	mov	ax,dseg
	mov	ds,ax	
;-----------------------------------------------------------
		mov dx, offset poch
		mov ah, 9 
		int 21h
 ;----------------------------------------------------------
	mov si, 0
	c0: mov ah, 01h
	int 21h
	cmp al, 27
	je c1
	mov buf[si], al
	inc si
	inc c
	jmp c0
  ;----------------------------------------------------------
c1:		mov		dx,offset newcat	; створення нового каталога 
		mov		ah,39h
		int		21h
		jc		erop
  ;-----------------------------------------------------------
		mov		dx,offset newcat	; перехід в створений каталог 
		mov		ah,3bh
		int		21h
		jc		erop
  ;-----------------------------------------------------------
		mov		dx,offset newfile  	; створення і відкриття нового файлу
		mov		cx,0	
		mov		ah,5bh
		int		21h
		jc		erop
		mov		bx,ax			; пересилання ідентифікатора файлу
  ;--------------------------------------------------------------------
		mov		dx,offset buf	; запис у файл
		mov		cx,si
		mov		ah,40h
		int		21h
		jc		erop
		
  ;--------------------------------------------------------------------
		mov		ah,3eh		 	; закриття файлу
		int		21h
		jc		erop
  ;--------------------------------------------------------------------
 mov 		 dx,offset rootcat           	; перехід в кореневий каталог 
 mov 		 ah,3bh
 int 		 21h
 jc		 erop
  ;--------------------------------------------------------------------
exit:		mov		ax,4c00h		; вихід з програми
		int		21h
 ;--------------------------------------------------------------------
erop:		mov		dx,offset error	       ; виведення повідомлення про помилку на екран
		mov		ah,9
		int		21h	
		jmp		exit
cseg		ends
		end		start
/
	
	Створений каталог
/
Створений файл з іменем батька
/
Задача  3
Перейти у каталог (прізвище студента), відкрити файл (ім’я студента), прочитати текст (ім’я батька), вивести текст на екран, закрити файл, знищити файл, перейти в кореневий каталог, знищити каталог( прізвище студента).
sseg	segment	stack			; опис стеку
	db	256 dup (?)
sseg	ends
 ;---------------------------------------------------------
dseg	  segment				; опис даних
cat	  db	'\Lutsyshyn',0
file      db      'Ihor',0
buf	  db	256 dup(?)
bufend    db      '$'
rootcat   db      'c:\',0
error	  db	'error$'
dseg	  ends	
 ;-------------------------------------------------------------
cseg	segment				; типовий початок програми
	assume	cs:cseg;ds:dseg;ss:sseg
start:	jmp	main
main:	push	ds	
	mov	ax,0
	push	ax
	mov	ax,dseg
	mov	ds,ax				; пересилання ідентифікатора файлу
  ;-----------------------------------------------------------
	mov	dx,offset cat	   		; перехід в існуючий каталог
	mov	ah,3bh
	int	21h
	jc	erop
 ;-----------------------------------------------------------
	mov	dx,offset file        		; відкриття існуючого файлу
	mov	al,0
	mov	ah,3dh
	int	21h
	jc	erop
	mov	bx,ax
 ;-------------------------------------------------------
	mov	dx,offset buf			; читання байтів у буфер
	mov	cx,10	
	mov	ah,3fh
 	int	21h
	jc	erop
 ;-------------------------------------------------------
	mov	ah,9				; вивід вмісту буфера на екран
	int	21h
 ;-------------------------------------------------------
	mov	ah,3eh				; закриття файлу
	int	21h
	jc	erop
 ;--------------------------------------------------------
	mov	dx,offset file 	  		; видалення файлу
	mov	ah,41h
	int	21h
	jc	erop
 ;--------------------------------------------------------------------
   	mov  	   dx,offset rootcat			 ; перехід в кореневий каталог
mov   	  ah,3bh
int    	 21h
jc     	erop
 ;--------------------------------------------------------------------
     	mov	dx,offset cat   			; видалення каталога
	mov	ah,3ah
	int	21h
	jc	erop
 ;-------------------------------------------------------------------- 
exit:	mov	ax,4c00h			; вихід з програми
	int	21h
 ;-------------------------------------------------------------------
erop:	mov	dx,offset error			; вивід повідомлення про помилку на екран
	mov	ah,9
	int	21h	
	jmp	exit
cseg	ends
	end	start
Каталог видалений
/ЛІТЕРАТУРА 
Р. Джордейн. Справочник программиста персональных комп’ютеров типа IBM PC, XT и АТ.
Зубков С.В. Assembler для DOS, Windows и Unix.