commit be2b9502d12c7746c6e7e473b9cfaeb6e7300237 Author: Mark Zheleznyakov Date: Sat Sep 7 08:49:36 2024 +0300 init diff --git a/ASMOUSE.CPP b/ASMOUSE.CPP new file mode 100755 index 0000000..02156ba --- /dev/null +++ b/ASMOUSE.CPP @@ -0,0 +1,131 @@ +/**************************************************************************** +** Эта программа демонстрирует, как можно добиться взаимодействия с мышкой,** +** используя С++ и Ассемблер. ** +****************************************************************************/ + +#include +#include +#include +#include + +//Глобальные переменные, хранящие координаты и признак нажатия на кнопку +//мыши. +unsigned int MouseX, MouseY, MouseB; + +char IfMouse (); +void ShowMouse (); +void HideMouse (); +void ReadMouse (); +void SetMouseXY (unsigned int X, unsigned int Y); +void SetMinMaxX (unsigned int Min, unsigned int Max); +void SetMinMaxY (unsigned int Min, unsigned int Max); + +//Эта процедура проверяет доступна ли мышь +char IfMouse () +{ + unsigned int Result; + asm mov ax, 0 + asm int 0x33 + asm mov Result, ax + return Result; +} + +//Эта процедура делает видимым курсор мыши +void ShowMouse () +{ + asm mov ax, 0x1 + asm int 0x33 +} + +//Эта процедура делает невидимым курсор мыши +void HideMouse () +{ + asm mov ax, 0x2 + asm int 0x33 +} + +//Эта процедура считывает положение курсора мыши и признак нажатия +//на клавишу +void ReadMouse () +{ + asm mov ax, 0x3 + asm int 0x33 + asm mov MouseB, bx + asm mov MouseX, cx + asm mov MouseY, dx +} + +//Эта процедура устанавливает курсор в другие координаты +void SetMouseXY (unsigned int X, unsigned int Y) +{ + asm mov ax, 0x4 + asm mov cx, X + asm mov dx, Y + asm int 0x33 +} + +//Эта процедура устанавливает минимальное и максимальное значение +//границ промежутка, в котором может двигаться курсор мыши +//в горизонтальном положении. +void SetMinMaxX (unsigned int Min, unsigned int Max) +{ + asm mov ax, 0x7 + asm mov cx, Min + asm mov dx, Max + asm int 0x33 +} + +//Эта процедура устанавливает минимальное и максимальное значение +//границ промежутка, в котором может двигаться курсор мыши +//в вертикальном положении. +void SetMinMaxY (unsigned int Min, unsigned int Max) +{ + asm mov ax, 0x8 + asm mov cx, Min + asm mov dx, Max + asm int 0x33 +} +//Главная пограмма - тестирует мышь и процедуры описанные выше. +main(){ + clrscr(); + IfMouse(); + cout<<"Мышь доступна в системе.\n"; + delay(3000); + cout<<"Сейчас появится курсор - задержка 3 сек.\n"; + delay(3000); + ShowMouse(); + cout<<"Сейчас курсор исчезнет - задержка 3 сек.\n"; + delay(3000); + HideMouse(); + cout<<"Через 3 сек курсор появится вновь.\n"; + delay(3000); + ShowMouse(); + ReadMouse(); + cout<<"\nКоординаты мыши на момент #1:\n"; + cout<<"Х-координата: "< +#include +#include +#include +#include +#define Port8042 0x60 + +long far * pTime=(long far*)0x46C; // Указатель на счетчик тиков + +// Определим указатели начала и конца буфера + +int far * pHeadPtr=(int far *)0x41A; // Указатель на указатель головы буф.кл. +int far * pTailPtr=(int far *)0x41C; // Указатель на указатель хвоста буф.кл. +unsigned char far * pBuf; + +void main() +{ +// 3адание N1. + clrscr(); + + cout << "\n 3адание N1:\n"; + cout << "\n Нажимайте клавиши для получения кодов!"; + cout << "\n Пробел - идем дальше.\n"; + char cScan,cAsci; + int iAdres; + do + { + // Загрузить пару регистров, например ds:si значением 0x40:0x1A + asm{ + push ds // + push si // Сохранили регистры + push di // + mov ax,0x40 // + mov ds,ax // Загрузили сегмент + mov si,0x1A // и указатели на голову + mov di,0x1C // и на хвост + } + wait_kbd: + asm{ + mov ax,[si] // Сравниваем указатели - + cmp ax,[di] // т.е. ждем нажатия + je wait_kbd + // Загрузить регистр di значением 0x1C + // Сравнить указатели + // Прочитать указатель + mov si,[si] + } + iAdres=_SI; + // Прочитать значение из буфера + asm mov ax,[si] + // Теперь _AL и _AH содержат скан-код и ASCII-код + asm pop di + asm pop si + asm pop ds + cScan=_AH; + cAsci=_AL; + printf("Адрес = %x Скан = %d ASCII = %d \n",iAdres,cScan,cAsci); + } while(getch() != 32); + cout << "\n Конец первого задания. Press any key...\n"; + getch(); + + delay(1000); + asm in al,0x60 + cScan=0; // ?????? + printf(" Скан = %x \n",cScan); +// goto met; +// +} +// Задание +// 1 Разберите представленную программу +// Определите отличие ASCII кодов: основных и служебных клавиш +// 2 Напишите мини программу циклического чтения скан кодов из порта 60 +// Определите отличие скан кодов: нажатия и отпускания клавиши diff --git a/LABV11.CPP b/LABV11.CPP new file mode 100755 index 0000000..697e191 --- /dev/null +++ b/LABV11.CPP @@ -0,0 +1,40 @@ +/* Лабораторная работа 11 + Видеоадаптер, графические режимы sVGA +*/ +#include +#include +#include + +void set_mode(int mode) +{ + asm{ + mov ax,0x4f02; + mov bx,mode ; + int 0x10; + } +} + +void main(void) +{ +set_mode(0x0112); +unsigned char c=0; +for (int i=2; i<640*4;i+=4) +{ +asm { + mov ax,0xa000; + mov es,ax; + mov si,i + mov bh,c + mov bl,c + mov es:[si],bl + + } + + c++; +} +getch(); +set_mode(0x3); +} +// Задание +//Определите в каком порядке кодируются цвета в 111 и 112 режимах +//Напишите программу вывода полутонового клина на Асс diff --git a/LABV5.CPP b/LABV5.CPP new file mode 100755 index 0000000..4f8349d --- /dev/null +++ b/LABV5.CPP @@ -0,0 +1,57 @@ +// Работа N LAB5 +// Шаблон программы +// Тема - ПОДПРПОГРАММЫ + +#include +#include +#include + +/* +При вызове функции в Си, она интерпретируется как команда Call +в Assembler. При этом передаваемые в функцию параметры, заносятся в +СТЕК по принципу справа налево. Затем заносится IP следующей команды, +идущей за Call. (внутрисегментный вызов процедуры) +Выход из функции осуществляется с помощью команды RET. +*/ + +//Функция, выполняющая сложение, параметры перед через стек +void addition(long sl_1,long sl_2, long &sum) +{ +/* asm{ + mov AX,[BP+4] //AX - младшие pазpяды пеpвого слагаемого + mov DX,[BP+8] //DX - младшие pазpяды второго слагаемого + mov SI,[BP+12] //SI - сумма младших pазpядов + add AX,DX //сложение младших pазpядов + mov [SI],AX //pезультат косвенно в SI + mov AX,[BP+6] //AX - стаpшие pазpяды пеpвого слагаемого + mov DX,[BP+10] //DX - младшие pазpяды второго слагаемого + //сложение стаpших pазpядов + mov [SI+2],AX //pезультат в SI + }*/ + sum=sl_2; +} + +void main ( void ) +{ +long a,b; +long sum; + +cout<<"\n Введите первое слагаемое: "; +cin>>a; +cout<<" Введите второе слагаемое: "; +cin>>b; + +addition(a,b,sum); + +cout<<"a + b = "< +#include +#include +#include + +void interrupt (*old)(...); // здесь будем сохранять старый вектор +void interrupt cmp_int(...) // а это наш обработчик +{ +cout<<"Прерывание "; +getch(); + +} + +void main(void) +{ int aa; + aa=1; + old=getvect(0xf0); + disable(); + setvect(0xf0,cmp_int); + enable(); +// aa=aa/0; + geninterrupt(0xf0); + + puts("v1=v2"); + setvect(0xf0,old); + return; +// Задания +// 1 Напишите программу обработки прерывания +// 2 Вызовите прерывание путем организации особого случая +// 3 Покажите использование команды int3, определите ее код с испол. TD + } diff --git a/LABV7.CPP b/LABV7.CPP new file mode 100755 index 0000000..31d9c43 --- /dev/null +++ b/LABV7.CPP @@ -0,0 +1,41 @@ +/* LAB-7 + Лабораторная работа по теме + "Числа сплавающей запятой" + + */ +#include +#include +#include +#include +#include + +void main(void) +{ int aa; +// Операции с плавающей запятой на уровне Си + float bb,ad; + aa=1; bb=5.0;ad=3.1; + bb=aa; +cout<<"\n Ci "<>bb; +getch(); + +// Операции с плавающей запятой на уровне Ассемблера +asm { finit + fld ad + fld bb + fadd + fstp bb +} +cout<<" Acc "< +#include +#include +#include +#include + +#include ; + +union REGS r; + +void main() +{ +// Устан номера видеорежима + int j,i,ii,color=0; + r.h.ah=0x0; + r.h.al=0x13; +//_asm int 0x10; + int86(0x10,&r,&r); + // Вывод цветного клина + for( j =1 ; j <319 ; j ++) + { color=color+1; + _AH=0x0c; + _AL=color; + if(color==256) color=0; + _BH=0; + _DX=50; + _CX=j; + geninterrupt(0x10); + } + getch(); + +//Перепрограммирование таблицы палитры + ii=clock(); + for( i = 0 ; i < 255 ; i++) + { _AH=0x10; + _AL=0x10; + _BX=i; // Номер регистра + _CH=i; /* G */ + _CL=i; /* B */ + _DH=i; /* R */ + geninterrupt(0x10); + } /* */ + color=256; + i=clock()-ii; + +// Вывод полутонового клина + for( j =1 ; j <319 ; j ++) /* */ + { color=color-1; + _AH=0x0c; + _AL=color; + if(color==0) color=256; + _BH=0; + _DX=100; // строка вывода + _CX=j; + geninterrupt(0x10); + } +// printf("Время перепрограммирования табл палитр : %d",i); + getch(); + +// Задания +// 1 Подкрасьте полутоновой клин красным цветом +// 2 Выведите клин в режиме прямой работы с видео памятью +// (напишите Асс программу вывода возрастающ кода, начиная с a0000) +// 3 Измерьте время вывода и перепрограммир табл палитры используя i=clock() +// 4 Придумайте абстрактную анимацию, выведя несколько +// цветовых клиньев и циклически перепрограммируя табл палитры + return; +} \ No newline at end of file diff --git a/LOGOW2.BMP b/LOGOW2.BMP new file mode 100755 index 0000000..11859ad Binary files /dev/null and b/LOGOW2.BMP differ diff --git a/Lab_asm.asm b/Lab_asm.asm new file mode 100755 index 0000000..a50d677 --- /dev/null +++ b/Lab_asm.asm @@ -0,0 +1,17 @@ + DOSSEG + .MODEL TINY + .STACK 100h + .DATA +Message DB 13,10,'Hi ╧ЁштхЄ! ',13,10,'$' + .CODE + mov ax,@Data + mov ds,ax ; єёЄрэютшЄ№ ЁхушёЄЁ DS Єръшь + ; юсЁрчюь, ўЄюс√ юэ єърч√тры + ; эр ёхуьхэЄ фрээ√ї + mov ah,9 ; ЇєэъЎш  DOS т√тюфр ёЄЁюъш + mov dx,OFFSET Message ; ёё√ыър эр ёююс∙хэшх "╧ЁштхЄ!" + int 21h ; т√тхёЄш "╧ЁштхЄ!" эр ¤ъЁрэ + mov ah,4ch ; ЇєэъЎш  DOS чртхЁ°хэш  + ; яЁюуЁрьь√ + int 21h ; чртхЁ°шЄ№ яЁюуЁрььє + END \ No newline at end of file diff --git a/Labv1.cpp b/Labv1.cpp new file mode 100755 index 0000000..8c507b5 --- /dev/null +++ b/Labv1.cpp @@ -0,0 +1,226 @@ +// Пример оформления программы + +// Работа N 0 +// Измерение времени выполнения фрагмента программы +// Студенты гр 000.0 Иванофф, Петрофф, & Сидорофф +// + +#include +#include +#include +#include + +#define PortCan0 0x40 + + +void beep(unsigned iTone,unsigned iDlit); // Это прототип функции + // звукового сигнала, используемой при измерении времени + +void main(void) +{ + + // Объявление переменных +long int lCnt=0; // Ячейка - счетчик повторений +int iA=0x1234; // Думми-ячейка, используемая в исследуемой команде + +/*************************************************************************\ +/* Как из Си посмотреть содержимое байта с известным физическим адресом */ + + // Если хотим напечатать содержимое байта с адресом 0046Сh + //объявляем far-указатель на переменную типа char и инициализируем + //этот указатель значением адреса, предварительно преобразовав + //его к типу char * +char far * pT=(char *)0x46C; // (1) + printf ("\n Печатаем 10 раз значение байта с известным адресом \n"); + for (int i=0; i<10; i++) + printf (" \n %d ", * pT); // (1) + printf ("\n Для продолжения нажмите любую клавишу \n"); + getch(); // Программа ждет нажатия клавиши + + +/******************************************\ +\* Как из Си посмотреть содержимое порта */ + +// Читаем содержимое порта с адресом 40 с помощью функции Си + printf ("\n Читаем содержимое порта с адресом 40 с помощью функции Си \n" ); + // Цикл повторяется каждые 0.5 с + printf ("\n Для выхода из цикла - нажмите любую клавишу \n" ); + + + while (bioskey(1)==0) // пока не будет нажата любая клавиша + { + printf (" \n Порт40 = %d ", inp(PortCan0)); //(2) + // С помощью TD посмотрите, во что превращается ф-ция inp() + // на уровне машинных команд + delay(500); // Задержка на полсекунды (500 мс) + } + getch(); // Очищаем буфер клавиатуры +/**************************************************************************\ + Примечания: * +Функция printf (...) позволяет распечатать на экране значения переменных, * + а также произвольный текст. * +Функция bioskey(1) позволяет определить, нажата ли клавиша * +Функция inp(uPort) позволяет считать байт из порта Port * +Функция outp(uPort,iValue) позволяет вывести величину iValue в порт uPort * +Функция delay(uTime) организует программную задержку на uTime миллисекунд * +Функция getch() считывает один символ из буфера клавиатуры. * + В данном случае это надо для очистки буфера клавиатуры * +\**************************************************************************/ + +// Снова читаем тот же порт с помощью программы на встроенном ассемблере + printf ("\n Читаем содержимое порта с адресом 40 ассемблером \n" ); + + while (bioskey(1) == 0 ) // Этот цикл будет повторяться, + // пока не нажмем клавишу + + // Примеры использования встроенного ассемблера (3) + { + asm { push ax // Один способ записи на встроенном ассемблере + in al,0x40 + } + + unsigned char Tmm = _AL; // Эта команда эквивалентна mov Tmm,al + // !! Убедитесь в этом с помощью TD + + asm pop ax // Другой способ записи на встроенном ассемблере + delay (500); + printf (" \n Порт40 = %d ", Tmm ); + // Если нажата клавиша - то выход + } + getch(); + printf ("\n Для продолжения - нажмите любую клавишу \n "); + getch(); + +/************************************************************* + Как посмотреть содержимое длинной (например)четырехбайтовой + переменной с адреса 0046С c помощью средств Си */ + +long far * pTime=(long *)0x46C; // Указатель на счетчик тиков + while (bioskey(1) == 0) + { + printf ("\n %ld",*pTime); + delay(1000); + } + getch(); + // Читаем и печатаем содержимое двухбайтовой переменной + // с адреса 0046C средствами встроенного ассемблера + int Time; + while (bioskey(1) == 0) + { + asm push ds // Сохраним на всякий случай регистры + asm push si + // Во встроенном ассемблере + asm mov ax,40h // можно записывать hex-константы так ... + asm mov ds,ax + asm mov si,0x6C // ... или так + asm mov ax,[ds:si] + asm mov Time,ax + asm pop si // А теперь восстановим регистры + asm pop ds // (не перепутайте порядок !!!) + + printf ("\n %d",Time); + delay(300); + } + +/**************************************************************** + Пример выполнения задания типа И + Требуется измерить время выполнения заданной команды + (в примере - команда mov reg,mem, а Вы спросите у преподавателя + какую команду Вам взять ) + + Измерение времени выполнения фрагмента программы */ + + beep(400,200); // Сигнал отмечает начало интервала (5) + for ( lCnt=0; lCnt<1000000; lCnt++) + { +a1: asm { mov ax,iA + mov ax,iA + mov ax,iA + mov ax,iA + mov ax,iA + mov ax,iA + mov ax,iA + mov ax,iA + mov ax,iA +a2: mov ax,iA } + } + beep(400,200); // Сигнал отмечает конец интервала (5) +} + + // Функция подачи звукового сигнала заданной высоты и длительности (5) +void beep(unsigned iTone,unsigned iDlit) +{ sound(iTone); + delay(iDlit); + nosound(); +} + +// Результаты выполнения +// Запустили программу дважды +// При первом пуске участок между метками a1 и a2 был закомментирован +// Время выполнения составило 3.15 +- 0.2 секунд (для оценки ошибки +// прогон был повторен 5 раз и было оценено среднее значение и +// среднеквадратическое отклонение. Приведенный допуск равен 2*СКО) +// При втором пуске участок a1-a2 работал. Время выполнения +// составило 7.5 +- 0.2 секунд. Количество повторений команды MOV REG,MEM +// равно 10^7, добавка времени равна 4.35 +- 0.3 секунд, оценка времени +// выполнения команды 0.44 +- 0.03 мкс. +// С помощью TD определили, что компилятор использовал адресацию +// базовая со смещением [BP+disp] + +/* + Задание на выполнение работы LAB0-0 + +1. Прочитайте текст программы и выделите логически связные части, + поймите, что делают эти части. Разбирая текст, обратите внимание на + то, какие функции Си используются и зачем. Делая это, научитесь + пользоваться контекстным Help'ом + +2. Скомпилируйте программу и убедитесь, что в ней отсутствуют ошибки + +3. Запустите программу, наблюдайте результат и убедитесь, что Вы пони- + маете, что происходит. + +4. Научитесь, используя встроенный отладчик IDE: + Выполнить программу до заданной точки останова. На уровне +исходного Си-текста это можно сделать, используя пункты меню Run +и Debug/Breakpoints. + Проверить/изменить содержимое переменных после останова. +Используйте пункт меню Debug/Evaluate/Modify, +Debug/Inspect (горячая клавиша Alt/F4) либо Debug/Watches + Измерить время выполнения заданной преподавателем команды +так, как это сделано в программе LAB0 с командой MOV REG,MEM. + +5. Средствами отладчика TD в окне CPU (пункт меню View/CPU) научитесь: + - наблюдать/изменять содержимое регистров процессора (подумайте, ка- + кие регистры можно менять безболезнено (изменения в некоторых ре- + гистрах могут привести к фатальным для нормального выполнения + программы результатам) + - наблюдать/изменять ячейку памяти с известным физическим адресом: + (Прежде, чем писать куда-либо, хорошо было бы подумать: что это за + адрес - адрес ОЗУ(не использует ли этот адрес еще какая-нибудь + программа), адрес ПЗУ, существует ли физическое устройство, соот- + ветствующее данному адресу... +Варианты: + 1. 0x46C + 0x80000 + 0xF000:0xFFF0 + 2. 0x0040:0x6D + 0x8000:0x0010 + 0xFFFFE + 3. 0x41A + 0x80210 + 0xFFFF:0x100 + 4. 0x0040:0x1E + 0xD00000 + 0x8000:0x200 + 5. область памяти - 0x41A-0x43C + 0xD000:0x100 + 0xFFFF:0xE +- читать/писать в произвольный порт ввода/вывода (например: считать + порт 0x40 несколько раз - попробуйте объяснить наблюдаемый резуль- + тат; записать число 3 в 61 порт, потом быстро записать туда нуль); + +6. Определите в какие команды Ассемблера оттранслирован с языка СИ +оператор цикла. Напишите на уровне Ассемблера свой вариант цикла. +Сравните, результаты представте преподавателю. +*/ diff --git a/Labv12.CPP b/Labv12.CPP new file mode 100755 index 0000000..b0fe011 --- /dev/null +++ b/Labv12.CPP @@ -0,0 +1,87 @@ +/* Структура растрового ВМР файла + Лабораторная работа 12 +*/ +#include +#include + +typedef unsigned int WORD; +typedef unsigned long DWORD; +struct BITMAPFILEHEADER { + WORD bfType; + DWORD bfSize; // Размер файла + WORD bfReserved1; + WORD bfReserved2; + DWORD bfOffBits; +}; +struct BITMAPINFOHEADER{ + DWORD biSize; + DWORD biWidth; + DWORD biHeight; + WORD biPlanes; + WORD biBitCount; // Количество бит в пикселе + DWORD biCompression; + DWORD biSizeImage; + DWORD biXPelsPerMeter; + DWORD biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; +}; + + +void main(int c,char **a) +{ + FILE *in, *out; + highvideo(); +BITMAPFILEHEADER bfh; +BITMAPINFOHEADER bih; +/* FILE *po; +if(argc==0) return 0; +if(argc==2) { mode=257;} else mode=atoi(argv[2]); +po=fopen(argv[1],"rb"); +fread(&bfh,14,1,po); +fread(&bih,40,1,po); +if(bih.biBitCount!=8) return 1; +if(bih.biClrUsed==0){ cmax=256; } +else cmax=bih.biClrUsed; +*/ +cputs("(c) Rex Software'99 Bmp Universal Invertor v1.0"); +normvideo(); +cputs(""); + + int n,bpp; + if (c!=2) + { + puts("\nNeeds some bmps"); + return ; + } + + in = fopen(a[1], "rb"); + if ((out = fopen("inversed.bmp", "wb"))== NULL) + { + puts("Cannot open output file"); return ; + } + cprintf("\n"); + cputs("Please wait"); + for (int i=0;i<54;i++) { + int c=fgetc(in); + fputc(c,out); + if (i==28) bpp=c;} + if (bpp==8) + { + for (i=0;i<1024;i++) fputc(255-fgetc(in),out); + + while (!feof(in)) fputc(fgetc(in),out); + } + if (bpp==24) + { for (int i=0;i<54;i++) fputc(fgetc(in),out); + while (!feof(in)) fputc(255-fgetc(in),out);} + + fcloseall(); + printf("\n%s is %d bit-per-pixel color depth bitmap\n",a[1],bpp); + puts("Successsfully retrieved to Inversed.bmp"); +} +/* Задание +1. Напишите программу бинаризации изображения. +2. Напишите программу тестирования входного файла (8 - 24 бита) +обязательно используйте структуры для тестирования. +*/ \ No newline at end of file diff --git a/Labv13.cpp b/Labv13.cpp new file mode 100755 index 0000000..3ec4bfb --- /dev/null +++ b/Labv13.cpp @@ -0,0 +1,175 @@ +/* Лабораторная работа 13 + Видеоадаптер, графические режимы sVGA, VESA +*/ +#include +#include +#include +#include +#define LOWORD(l) ((int)(1)) +#define HIWORD(l) ((int)((l) >> 16)) +#define MYMODE1 113h //800x600x32k +#define MYMODE2 101h //640x480x256 +#define MYMODE3 105h //1024x768x256 + + int pattern_ust=1; + int current_b=0; + +/* struct Vesainfo { + int attr_m; + char attr_a; + char attr_b; + int h_ust; + int size; + unsigned segm_a; + unsigned segm_b; + void far (*fun)(); + int byte_str; + int resx; + int resy; + char xchsize; + char ychsize; + char kolvo; + char bit_pix; + char kolvobank; + char memmod; + char size_bank; + char pages; + char reserved; + char red_mask_s; + char red_mask_p; + char green_mask_s; + char green_mask_p; + char blue_mask_s; + char blue_mask_p; + char reserved_mask_s; + char reserved_mask_p; + char colour_info; + char reserved2[216]; + }mine; */ + + +struct SvgaModeInfo +{ + unsigned state; + char a_window_state; + char b_window_state; + unsigned window_multiplicity; + unsigned window_size; + unsigned a_window_segment; + unsigned b_window_segment; + void far (*fun)(); + unsigned string_width; + unsigned width; + unsigned height; + char symbol_height; + char symbol_width; + char switches_count; + char bits_per_pixel; + char banks_count; + char memory_model; + char bank_size; + char pages_count; + char reserved1; + char red_mask; + char red_bit; + char green_mask; + char green_bit; + char blue_mask; + char blue_bit; + char reserved_mask; + char reserved_bit; + char palette_state; + char lfb[10]; + char resrved2[206]; +}mine; + +void Bank_ust(int begin) +{ + if (begin==current_b) + return; + current_b=begin; + begin *= pattern_ust; + asm{ + mov ax,4F05h + mov bx,0 + mov dx,begin + push dx + int 10h + pop dx + mov bx,1 + int 10h + }; +} + +inline int RGBcolour(int red,int green,int blue) +{ + return ((red >> 3)<<10) | ((green >> 3)<<5) | (blue >> 3); +} +void set_text_mode() +{ + asm mov ax,0x0003 + asm int 0x10 +} +void draw(int x,int y,int colour) +{ + long ttt; + asm{ + mov dx,y //bank number + shr dx,6 + mov bx,0 + }; + mine.fun(); + ttt = (y*1024%65536)+x; + _SI = (unsigned int)ttt; + asm{ + mov ax,colour + mov bx,0xA000 + mov es,bx + mov es:[si],al + }; +} + +void paint(int begx,int begy,int endx,int endy,int colour) +{ + int x,y; + for(y=begy;y<=endy;y++) + for(x=begx;x<=endx;x++) + draw(x,y,colour); + +} +void main() +{ + int colour,x,y; + asm{ + //information + mov cx,MYMODE3 + lea di,mine + mov ax,ds + mov es,ax + + mov ax,0x4F01 + + int 10h + }; + asm{ //setting of this mode + mov ax,4F02h + mov bx,MYMODE3 + int 10h + }; + x=0; + y=0; + for(colour=1;colour<255;colour++){ + if(x>1024){ + x=0; + y=y+48; + } + paint(x,y,x+64,y+48,colour); + x=x+64; + } + getch(); + set_text_mode(); +} +// Задание +// 1. Выведите полутоновой клин во 2 банке памяти. +// 2. Определите как располагаются банки памяти на экране. +// \ No newline at end of file diff --git a/Labv14.cpp b/Labv14.cpp new file mode 100755 index 0000000..14dc1da --- /dev/null +++ b/Labv14.cpp @@ -0,0 +1,184 @@ +/* Лабораторная работа 14 + Объединение команд для их параллельного выполнения + (оптимизация уровня команд) + */ + +#include +#include +void NullProc(void){} +void ExTime(void (*PP)(void)) +{ + long far* pTime = (long*)0x46C; //счетчик тиков + long Time0, Time1, Time2, i; + + void (*NP)(void); + NP = NullProc; + Time0 = *pTime; + for (i = 1; i<1000000L; i++) + { + NP(); + NP(); + NP(); + NP(); + NP(); + NP(); + NP(); + NP(); + NP(); + NP(); + } + Time1 = *pTime; + for (i = 1; i<1000000L; i++) + { + PP(); + PP(); + PP(); + PP(); + PP(); + PP(); + PP(); + PP(); + PP(); + PP(); + } + Time2 = *pTime; + Time2 = (((Time2 - Time1) - (Time1 - Time0))*(6553500L/1193180L)); + printf("%ld нс\n",Time2); +} +void P1(void) //регистровые зависимости имеются +{ + asm{ + mov ax,bx + mov dx,ax + stc + adc bx,cx + stc + sbb dx,ax + + add ax,bx + mov cx,ax + sub dx,bx + mov bx,dx + } +} +void P2(void) //регистровые зависимости устранены +{ + asm{ + + + } +} +void P3(void) //другие причины неспаренности +{ + asm{ + mov cl,3 //непосредственный операнд + inc bx + mov cl,3 + dec bx + mov cl,3 + inc bx + mov cl,3 + dec bx + + inc bx //команды сдвига с cl в качестве счетчика + ror ax,cl + dec bx + rol ax,cl + + inc dx //команды с префиксами м. б. в U - конвейере + mov ax,ds:[bx] + mov ax,ss:[bx] + mov ax,es:[bx] + mov ax,cs:[bx] + mov cl,3 + mov cl,3 + mov cl,3 + dec dx + + inc dx //команды сдвига м. б. в U - конвейере + ror ax,1 + rol ax,1 + dec dx + } +} +void P4(void) //причины неспаренности устранены +{ + asm{ + + } +} +void main(void) +{ + clrscr(); + printf("Program1 - регистровые зависимости имеются\n"); + ExTime(P1); + printf("Program2 - регистровые зависимости устранены\n"); + ExTime(P2); + printf("Program3 - другие причины неспаренности\n"); + ExTime(P3); + printf("Program4 - причины неспаренности устранены\n"); + ExTime(P4); + getch(); +} + +//Задание +// 1. Устраните причины неспаренности команд. +// 2. Определите и объясните время выполнения фрагментов программ. +// +/* ПРАВИЛА ОБЪЕДИНЕНИЯ КОМАНД +Процессор Pentium может выполнять одну или две команды в каждом +такте. Для выполнения в процессоре одновременно двух команд они +должны удовлетворять следующим условиям: + +-обе команды в паре обязаны быть <простыми> в смысле, определенном +ниже; +-между ними не должно быть регистровых зависимостей типа чтение- после- +записи или запись-после-записи (read-after-write or write-after-wnte) , +-ни одна из команд не может содержать смещение (displacement) и +непосредственный операнд; +-команды с префиксами (за исключением OF в командах перехода JCC) +могут встречаться только в U-конвейере. + Под простыми командами понимаются команды, управление +выполнением которых осуществляется аппаратно, без использования +микрокоманд, и которые реализуются за один такт. Исключением являются +команды ALU mem, reg и ALU reg, mem, требующие трех и двух тактов для +выполнения соответственно. Специальные аппаратные средства +используются для их выполнения как простых команд. Следующие +целочисленные команды рассматриваются в качестве простых и могут быть +спарены: +-mov reg, reg/mem/imnl +-mov mem, reg/imm (команды передачи) ; +-alu reg, reg/mero/imm (команды арифметических +- alu meln , reg/ imm и логических операций) ; +- inc reg/mem (команды инкремента, +- dec reg/mem (декремента) ; +-push reg/mem (команды обращения +- pop reg (к стековой памяти) ; +-lea reg,mem (команды загрузки сегментных регистров) ; +-jmp/call/jcc near (команды передачи управления) ; +-nор (пустая команда) . + Команды безусловной и условной передач управления могут +о6ьединяться в пары, если они встречаются в качестве вторых команд в паре. +Они не могут быть спарены со следующей последовательной командой. Также +команды SHIFT/ROT со сдвигом на один разряд и SHIFT на произвольное +число разрядов могут спариваться только как первые ( команды в паре). + Регистровые зависимости + Регистровые зависимости, запрещающие спаривание команд, включают +неявные зависимости через регистры или флаги, не указанные в команде. +Все виды зависимостей по данным могут быть классифицированы по +типу ассоциаций: RAR - "чтение после чтения", WAR - "запись после чтения" и +WAW - "запись после записи", RAW - "чтение после записи". Некоторые из +зависимостей по данным могут быть устранены. RAR, по сути дела, +соответствует отсутствию зависимостей, поскольку в данном случае порядок +выполнения команд не имеет значения. Действительной зависимостью является +только "чтение после записи" (RAW), так как необходимо прочитать +предварительно записанные новые данные, а не старые. + Лишние зависимости по данным появляются в результате "записи после +чтения" (WAR) и "записи после записи" (WAW). Зависимость WAR состоит в +том, что команда должна записать новое значение в ячейку памяти или регистр, +из которых должно быть произведено чтение. Лишние зависимости появляются +по нескольким причинам: не оптимизированный программный код, ограничение +количества регистров, стремление к экономии памяти, наличие программных +циклов. + +*/ diff --git a/Labv15.cpp b/Labv15.cpp new file mode 100755 index 0000000..c71a30e --- /dev/null +++ b/Labv15.cpp @@ -0,0 +1,256 @@ +/* Лабораторная работа 15 + Saund Blaster + FM синтез +Задание +1. Проиграйте гамму, вызовите спецэффекты +2. Сыграйте мелодию +*/ +#include +#include +#include +#include +#include +#include + +#define KEYON 0x20 // key-on bit in regs b0 - b8 +#define FM 8 // SB (mono) ports (e.g. 228H and 229H) + +unsigned IOport=544; // Sound Blaster port address + +void mydelay(unsigned long clocks) +// time = clocks / 2386360 +{ + unsigned long elapsed=0; + unsigned int last,next,ncopy,diff; + + /* Read the counter value. */ + outp(0x43,0); /* want to read timer 0 */ + last=inp(0x40); /* low byte */ + last=~((inp(0x40)<< 8) + last); /* high byte */ + + do { + /* Read the counter value. */ + outp(0x43,0); /* want to read timer 0 */ + next=inp(0x40); /* low byte */ + ncopy=next=~((inp(0x40)<< 8) + next); /* high byte */ + + next-=last; /* this is now number of elapsed clock pulses since last read */ + + elapsed += next; /* add to total elapsed clock pulses */ + last=ncopy; + } while (elapsed> 8) & 0x3) + (block << 2) | KEYON); + getche(); + } + + + /***************************************************************** + * Generate a range of frequencies by changing frequency number. * + *****************************************************************/ + + printf("Range of frequencies created by changing frequency number.\n"); + block=4; + for (fn=0; fn<1024; fn++) { + fm(0xA0,(fn & 0xFF)); + fm(0xB0,((fn >> 8) & 0x3) + (block << 2) | KEYON); + delay(1); + } + + /********************************* + * Attenuate the signal by 3 dB. * + *********************************/ + + getche(); + fm(0xB0,((fn >> 8) & 0x3) + (block << 2) | KEYON); + printf("Attenuated by 3 dB.\n"); + fm(0x43,4); /* attenuate by 3 dB */ + getche(); + + fm(0xB0,((fn >> 8) & 0x3) + (block << 2)); + + exit(0); +} + + +unsigned int x; +FILE *fp; +char buf,key; +unsigned long playtime,showtime; +unsigned char gstring[80]; + + +int main ( int argc, char *argv[] ) +{ +//---------------- +// Initialize DSP for Voice +//------------- + outportb(0x0226,0x01); + delay(3); + outportb(0x0226,0x00); + for(x=0;x<100;x++) + { + if(inportb(0x022E)&0x80) + { + if(inportb(0x022A)==0xAA) break; + } + } + if(x==100) + { + printf("Sound Blaster not found at 0220h\n"); + exit(1); + } +//------------ +// Menu +//----------------- + clrscr(); + printf("1) Play original\n2) Play reduced\n3) FM Synth\n4) Exit\n"); + key=getch(); + if (key=='4') exit(0); + if (key=='3') midimain(); +//------------ +// Read file & play +//----------------- + clrscr(); + printf("Program compiled for Sound Blaster ver. 1.0 (8bit 44100Hz mono).\n\n"); + if (key=='1') printf("Normal play.\n"); + if (key=='2') printf("Reduced play.\n"); + printf("Playing .wav ...\n\n"); + if(argc==1) + { + printf(".WAV file not specified\n"); + exit(1); + } + strcpy(gstring,argv[1]); + strcat(gstring,".WAV"); + if((fp=fopen(gstring,"rb"))==0) + { + strcpy(gstring,argv[1]); + if((fp=fopen(gstring,"rb"))==0) + { + printf("Error opening .WAV file [%s]\n",argv[1]); + exit(1); + } + } + printf("FILE: [%s]\n",gstring); + fseek(fp,36L,SEEK_SET); + while (inportb(0x022C)&0x80); + outdsp(0xD1); //speaker on + playtime=0; + while (fread(&buf,1,1,fp)!=0) + { + if(key=='2') fread(&buf,1,1,fp); + if(key=='2') mydelay(15); + if(key=='2') playtime++; + if(key=='2') showtime=playtime/100000; + if(key=='2') if (showtime*100000== playtime) printf("Time: %u \r",showtime); + outdsp(0x10); + outdsp(buf); + mydelay(15); + playtime++; + showtime=playtime/100000; + if (showtime*100000== playtime) printf("Time: %u r",showtime); + + } + outdsp(0xD3); //speaker off + fclose(fp); + return 0; +}; diff --git a/Labv2.cpp b/Labv2.cpp new file mode 100755 index 0000000..5724f10 --- /dev/null +++ b/Labv2.cpp @@ -0,0 +1,289 @@ +// Шаблон программы для лаб работы LAB2 +// Изучение системы команд + +#include +#include + +int main (void) +{ int aa; + + clrscr(); +/* +******************************************************** + 1 2 3 Напишите программы, иллюстрирующие работу след команд: + +1. Команда JL. + JL metka. + Осуществляет переход на указанную метку, + если результат предыдущего сравнения: БОЛЬШЕ + (Переход осуществляется, если флаги SF=0 и OF =0) + + asm { + cmp ax, 13 + JL metka + ..... ; какой-то блок команд + + metka: + ...... ; какой-то блок команд + }; + +2. Команда ROL + Rol ax, 1 + Rol bx, cl + + Команда циклического сдвига влево. + Если второй операнд - CL, то число разрядов, на которые + осуществляется сдвиг, определяется содержимым регистра CL. + +3. Команда LEA. + По этой команде адрес второго операнда передается в регистр + первого операнда. + lea ax, a; + +4. Команда NOP + Команда нет операции + +5. Команда AND + and ax,bx + Команда логического умножения + Первый операнд лог умножается (конъюнкция) на второй + результат в первый */ +/* +******************************************************** + 4 Напишите программу со строковыми командами + Команда MOVS. + Команда пересылки строки. + Направление пересылки определяется значением флага DF - флага направления. + + Для операций с байтами - MOVSB + Для операций со словами - MOVSW + + Не имеет операндов. Не воздействует на флаги. + + Пересылает из области памяти, адресуемой регистром SI - sourse + в область памяти, адресуемую регистром DI - destination. + + */ +// Ниже приведен пример программы + int A[10]={2,1,2,3,4,5,6,7,8,9}; + int B[10]={1,1,0,0,0,0,0,0,0,0}; + + asm { + cld //сбрасываем флаг направления + lea si,A + lea di,B +// mov dx,di + }; +// Задание: Распечатайте значения индексных регистров +// до передачи +// printf ("\n значения индекс регистров is, di = %x %x ", _SI, _DI); + asm mov cx,1 ; // ???? + asm movsb ; // ????? + +// Задание: Распечатайте значения индексных регистров +// после передачи Передача прошла? Сколько слов передано? + +printf ("\n значения индекс регистров is, di = %x %x ", _SI, _DI); + printf ("\n Вывод массива В после строковой передачи"); + for (int i=0; i<10; i++) + { + printf (" \n %d ", B[i]); + } + + getch(); + +//******************************************************** +// 5 Программа поиска в видеопамяти символа + printf (" \n Поиск символа "); +/* asm + asm +e1: asm { + mov ax, 0xb800 + mov es, ax + mov + cmp es:[di],al + jnz e2 }; + printf (" \n Нашли символ "); +e2: asm add di, 2 + asm loop e1 + printf (" \n Не нашли символ "); + getch(); + + */ +// return (0); +//***************** Задания ****************** +// +// 1 Проиллюстрируйте программами указанные выше команды +// 2 Рассмотрите двоичный код этих команд +// 3 Заполните таблицу, используя TD. Должны присутствовать +// все поля формата команды. +/* + Мнемоника Префикс КОП Постбайт Смещение Непоср.операнд + │ │ │ │ │адресации │ │ │ + ├────┼─────────────┼──────┼──────┼────────────┼─────────┼─────────────┤ + │ 1 │and ax,bx │ - │ │ │ - │ - │ + │ 2 │rep and bx,ax│ │ │ │ │ │ + │ 3 │add ax,16 │ - │ │ │ - │ │ + 4 add al,[bx+si] +*/ + +// 4. Напишите программу со строковыми командами при 10 передачах +// 5. Разработайте блок-схему и напишите программу +// поиска символа в видеопамяти на первых 4-х видеостраницах +// 6. Ответьте на вопросы: Какая мнемоника двухоперандной команды 00FF. +// Как выполняется команда LDS BX,PtriA + +/* + +  _Структура процессора i8086 + + Программисту на уровне команд доступны четырнадцать регист- +ров. Их удобно разбить на четыре группы: 1)Регистры данных, 2)ад- +ресные, 3)сегментные 4)указатель команд и регистр флажков(призна- +ков). +1) Регистры данных (в некоторых книгах их называют регистрами общего + назначения). Операнды в этих регистрах могут быть как слова так и + байты. Если операнд - байт, может быть указана любая половина + регистра. Есть ряд команд, в которых функции отдельных регистров + специализированы (см.табл.) +2) Указатели и индексные регистры (адресные регистры, используются для + хранения 16-разрядных адресов). Адресные регистры во многих командах + также специализированы (см.табл.) +3) Сегментные регистры (указывают начала четырех сегментов - участков + по 64 К байт в 1М ОЗУ: сегмент команд CS, сегмент стека SS и два + сегмента данных - DS и ES extra) +4) Указатель команд и регистр флажков + + Специальные функции регистров 8086 + +AX Аккумулятор Умножение, деление и ввод-вывод слов +AL Аккумулятор(мл) Умножение, деление и ввод-вывод байтов +AH Аккумулятор(ст) Умножение и деление байтов +BX База Базовый регистр, преобразование (?) +CX Счетчик Операции с цепочками, циклы +CL Счетчик (мл) Динамические сдвиги и ротации +DX Данные Умножение и деление слов, + косвенный ввод-вывод +SP Указатель стека Стековые операции +BP Указатель базы Базовый регистр +SI Индекс источника Операции с цепочками, индексный регистр +DI Индекс получателя Операции с цепочками, + +  _Регистр флагов процессора + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ + OF DF IF TF SF ZF AF PF CF + + CF ( Carry Flag ) - флаг переноса; + PF ( Parity Flag ) - флаг четности; + AF ( Auxiliary Carry Flag ) - флаг вспомогательного переноса; + ZF ( Zero Flag ) - флаг нуля; + SF ( Sign Flag ) - флаг знака; + TF ( Trap Flag ) - флаг ловушки; + IF ( Interrupt-Enable Flag ) - флаг разрешения прерывания; + DF ( Direction Flag ) - флаг направления; + OF ( Overflow Flag ) - флаг переполнения. + + + + + + - 5 - + +  _Организация памяти + + Адресуемая память (адресное пространство) представляет собой +область из 1М байт(в реальном режиме работы для микропроцессоров +i80286 и старше). Два смежных байта образуют слово. Адресом слова +считается адрес младшего байта. МП 8086 считывает информацию из +ОЗУ 16 бит.словами, начинающимися с четных адресов, хотя команда +или слово данных могут быть расположены в ОЗУ в любом адресе. + Физический адрес памяти имеет длину 20 бит, однако все обра- +батываемые в регистрах МП величины имеют длину 16 бит. Для форми- +рования физических адресов используется механизм сегментации памя- +ти. Пространство памяти 1 М доступно процессору через 4 "окна" +(сегмента) каждый размером 64 К байт. Начальный адрес каждого сег- +мента содержится в оюном из четырех сегментных регистров. Команды +обращаются к байтам и словам в пределах сегментов, используя отно- +сительный (внутрисегментный) адрес. + +  _Общий формат команды следующий: + +[Префикс] КОП [постбайт адресации] [смещение] [непоср.операнд] +Элементы в квадратных скобках могут отсутствовать. + + Назначение элементов команды: + + _Префикс .. Длина 1 байт. + а)Префикс переназначения сегмента позволяет переназначить сегмент + ОЗУ, к которому происходит обращение.Если префикс переназначения + сегмента отсутствует, сегмент выбирается по умолчанию. + б)Префикс повторения действия для строковых команд + _КОП . - код операции. Длина 1 байт. 0-й бит КОП во многих (но не во всех) + командах показывает, производится ли операция со словом ( =1) или с + байтом ( =0). 1-й бит КОП в двухадресных командах указывает, какой + из операндов является приемником. + _Постбайт адресации .. Длина 1 байт. Постбайт адресации показывает, где + находятся операнды. Структура системы адресации МП 8086 в + двухоперандной команде несимметрична. Один из операндов (первый) может + быть расположен в регистре (регистровая адресация) или в произвольной + ячейке ОЗУ (все способы адресации кроме непосредственной). + Второй операнд может находиться в теле команды (непосредственная + адресация) или в регистре (регистровая адресация). Каждый из + операндов может быть как источником так и приемником (за исключением + непосредственной адресации: непосредственный операнд может быть + только источником). Структура постбайта адресации следующая: + + 7 6 5 4 3 2 1 0 + ! mod ! reg ! r/m ! + !-----!-----!-----!-----!-----!-----!-----!----! + + Поля mod и r/m задают место расположения первого операнда (или + едиственного в одноадресной команде). Поле reg задает положение + второго операнда в двухадресных командах, или используется для + расширения КОП в одноадресных командах. + Значения поля mod: + 11 - операнд в регистре + (при остальных mod операнд в ОЗУ, а регистры, на + которые указывают поля mod и r/m, содержат компоненты + адреса операнда) + 10 - смещение два байта (без знака) + + - 6 - + + 01 - смещение один байт (со знаком) + 00 - смещение в команде отстутствует + + Значения поля reg а также поля r/m при mod=0 (т.е. при регистровой + адресации следующие: + + reg или r/m Байт Слово + 000 AL AX + 001 CL CX + 010 DL DX + 011 BL BX + 100 AH SP + 101 CH BP + 110 DH SI + 111 BH DI + + При адресации в память значения mod и r/m определяют способ + вычисления адреса следующим образом: + + r/m mod=00 mod=01 или 10 + 000 BX+SI BX+SI+смещение + 001 BX+DI BX+DI+смещение + 010 BP+SI BP+DI+смещение + 011 BP+DI BP+DI+смещение + 100 SI SI+смещение + 101 DI DI+смещение + 110 direct BP+смещение + 111 BX BX+смещение + +Смещение. Длина 1 байт (при mod-01) или 2 байта(при mod=10). +Непосредственный операнд. Длина 1 или 2 байта +Таким образом, длина команды лежит в пределах от 1 до 7 байтов. + +*/ +}; diff --git a/Labv3.cpp b/Labv3.cpp new file mode 100755 index 0000000..6cb7aaa --- /dev/null +++ b/Labv3.cpp @@ -0,0 +1,69 @@ +// Работа LAB3 +// Шаблон программы +// Массивы и способы адресации + +// Директивы Препроцессора +// Включение файлов в которых описаны прототипы ф-ций +// с целью сообщения компилятору о типах ф-ций и их аргументах +#include +#include +#include +#include +// #pragma inline // Подключение встроенного Ассемблера + +// Объявление переменных +int iB=0x1234; +int A[90]={0,1,2,3,4,5,6,7,8,9}; + +// Основная программа - функция +// void - она не возвращ значений +void main(void) +{ +// Объявление переменных +int iA=0x5678; + clrscr(); + printf ("\n Программа заполнения массива \n"); +// Заполняем массив на уровне команд Си + for (int i=0; i<10; i++) + { + // ??????? Вставте команды + printf (" \n %d ", A[i]); + } + getch(); +// Заполняем массив из ассемблера +asm mov si,0 +e2: +asm { + lea bx,A + mov cx,10 + mov ax,0 + }; +e1: asm mov [bx],ax // ???? Выберите способ адресации + asm add bx,2 + asm loop e1 +// ??? Выведите одном массив + asm add si,10 // Задается шаг массива + asm mov ax,100 + asm cmp ax,si + asm ja e2 +// ??? Выведите двумерный массив + for (i=0; i<20; i=i+4) + { printf (" \n "); + for (int j=0; j<4; j++) + { printf (" "); // ???? Вставте команду + } + } + getch(); +} + +// Задания +// 1. Напишите две программы заполнения одномерного массива на Си и Асс +// выведите на экран значения элементов массива +// 2. Считайте массив двумерным. Заполните его четные строки любым числом, +// используя разные способы адресации +// - косвенно-регистровая адресация +// - базово-индексная адресация +// Сравните количество команд при двух способах адресации. +// 3. Определите место массива в сегменте данных с использов. TD +// 4. Напишите программу, которая дает разный результат в разных +// моделях памяти. \ No newline at end of file diff --git a/Labv4.cpp b/Labv4.cpp new file mode 100755 index 0000000..1890649 --- /dev/null +++ b/Labv4.cpp @@ -0,0 +1,141 @@ +// Лабораторная Работа Lab 4 +// ТАЙМЕР. Измерение времени. Мышь +// + + +#include +#include +#include + +void main() +{ + long int cl2,cl1,c1,c2; + unsigned long int t1,t2,t3; + +// Изменение константы счетчика +/* asm{ + mov ax,00110110B // 00 11 011 0 + out 43h,ax + mov ax,0000000000000000B + out 40h,al + mov al,ah + out 40h,al + } + */ + + // Измерение времени выполнения тестовой программы 1 +// в тиках (в прерываниях от 0-го канала таймера) +// Счетчик тиков ячейка 46С - младший байт первый + asm{ + mov ax,0x46 + mov es,ax + mov bx,0xC + mov ax,[es:bx] + mov cx,[es:(bx+2)] + } +// Запомните начальное значение младшее и старшее ??? +// cl2= ; cl1= ; + c1=cl2+cl1*0x10000; + + //Тестовая программа 1 + asm mov cx,1000 + met1: asm { + push cx + mov cx,1000 + } + met2: asm { + loop met2 + pop cx + loop met1 + } + +// + asm{ + mov ax,0x46 + mov es,ax + mov bx,0xC + mov ax,[es:bx] + mov cx,[es:(bx+2)] + } +// Запомните конечное значение ??? +// cl2=_AX; cl1= ; +// Длинное целое - +c2=cl2+cl1*0x10000; + +// clrscr(); +// printf("\nПервое - %d\n",c1); +// printf("Второе - %d\n",c2); + cout<<"\nВремя выполнения тестовой программы 1\n"; + cout<<"COUNTs: "< +#include +#include +#include + + +#include + +void page(char a) // Установка номера активной дисплейной стр. +{ + asm { + mov ah,0x05 + mov al,a + int 0x10 + } + +} + +void main() +{ +// установка видеорежима +asm{ + mov al,02h + mov ah,00h + int 10h + } page(0); + clrscr(); +// Вывод текста средствами Си + for(char n = 1; n <= 100; n++) +// -- здесь сам вывод - + +// Выод текста в режиме непосредств работы с видеопамятью + page(0); + asm mov cx,1000 // Задаем количество символов + asm mov di,0 // Обнуляем индекс +e1: asm { add di, 2 + mov ax, 0xb800 // Определяем начальный адрес + mov es, ax + mov al, cl + mov es: [di],al // Пересылаем четный первый байт в видеопамять + mov al, 4 + mov es: [di+1],al // Пересылаем нечетный второй байт + }; + asm loop e1 + + getch(); + + +// Задания +// 1 Выведите текст с использ Си. +// Раскрасте его зеленым цветом с использованием Асс. +// Определите время вывода в обоих случаях +// 2 Протестируйте размер текстовой дисплейной страницы.(Напишите +// программу на Асс вывода символов в начале и в конце дисплейной страницы) +// 3 Выведите текст на вторую дисп страницу +// 4 Организуйте переключение страниц +/* while (bioskey(1) == 0) +{ + page(0); delay(1000); + +} */ +return; +} diff --git a/MTASK.CPP b/MTASK.CPP new file mode 100755 index 0000000..06bf5f1 --- /dev/null +++ b/MTASK.CPP @@ -0,0 +1,166 @@ +#include +#include +#include +#include + +struct ProcStats //struktura soderjashaya kontext zadachi +{ + unsigned int rax, rbx, rcx, rdx; // 0 2 4 6 + unsigned int rsi, rdi, rbp, rsp; // 8 10 12 14 + unsigned int rcs, rds, res, rss; //16 18 20 22 + unsigned int rip, rflags, a, b; //24 26 28 30 +} Stats[3]; //massiv iz treh takih struktur + +unsigned int current_proc; //nomer tekushey zadachi +unsigned int stats_offset; //adres konteksta zadachi +void interrupt (*oldHandler)(...); //ukazatel na staryi obrabotchik preryvaniya + +void interrupt IntHandler(...) //svoy obrabotchik +{ + asm { + mov si, [current_proc]; //nomer procedury + mov cl, 5 //umnojaem nar 32 (razmer struktury) + shl si, cl + //mov ax, offset Stats + mov ax, [stats_offset] //pribavlyaem adres nachala massiva struktur + add si, ax //poluchaem adres nujnogo konteksta + pop ax //zapisyvaem v nego registry + mov [si+12], ax //bp + pop ax + mov [si+10], ax //di + pop ax + mov [si+ 8], ax //si + pop ax + mov [si+18], ax //ds + pop ax + mov [si+20], ax //es + pop ax + mov [si+ 6], ax //dx + pop ax + mov [si+ 4], ax //cx + pop ax + mov [si+ 2], ax //bx + pop ax + mov [si+ 0], ax //ax + pop ax + mov [si+24], ax //ip + pop ax + mov [si+16], ax //cs + pop ax + mov [si+26], ax //flags + mov ax, sp + mov [si+14], ax //sp + mov ax, ss + mov [si+22], ax //ss + + mov ax, [current_proc] //perehodim k sleduyushey zadache + inc ax + cmp ax, 3 + jb label1 + mov ax, 0 + } + label1: + asm { + mov [current_proc], ax //vychislyaem adres eyo konteksta + mov si, ax + mov cl, 5 + shl si, cl + //mov ax, offset Stats + mov ax, [stats_offset] + add si, ax //zagrujaem registry + mov ax, [si+22] //ss + mov ss, ax + mov ax, [si+14] //sp + mov sp, ax + mov ax, [si+26] //flags + push ax + mov ax, [si+16] //cs + push ax + mov ax, [si+24] //ip + push ax + mov ax, [si+ 0] //ax + push ax + mov ax, [si+ 2] //bx + push ax + mov ax, [si+ 4] //cx + push ax + mov ax, [si+ 6] //dx + push ax + mov ax, [si+20] //es + push ax + mov ax, [si+18] //ds + push ax + mov ax, [si+ 8] //si + push ax + mov ax, [si+10] //di + push ax + mov ax, [si+12] //bp + push ax + } + oldHandler(); //vyzyvaem staryi obrabotchik +} + +void Proc1(void); +void Proc2(void); +void Proc3(void); + +int main(void) +{ + unsigned int i, rd, rc, re, rs, ri0, ri1, ri2, f; + + for(i=0;i<3;i++) + memset(&Stats[i],0,sizeof(ProcStats)); + asm { //zapisyvaem registry vo vremennye peremennye + mov ax, cs + mov [rc], ax + mov ax, ds + mov [rd], ax + mov ax, es + mov [re], ax + mov ax, ss + mov [rs], ax + mov [ri0], offset Proc1 //adresa nachala procedur + mov [ri1], offset Proc2 + mov [ri2], offset Proc3 + pushf + pop ax + mov [f], ax + } + for(i=0;i<3;i++) //zapisyvaem znacheniya segmentnyh registrov, + { //flagov + Stats[i].rcs = rc; //i adresa nacha procedur + Stats[i].rds = rd; //v sootvetstvuyushye konteksty + Stats[i].res = re; + Stats[i].rss = rs; + Stats[i].rflags = f; + } + Stats[0].rip = ri0; + Stats[1].rip = ri1; + Stats[2].rip = ri2; + current_proc = 0; //tekushaya procedura - pervaya + stats_offset = (unsigned)&Stats; //adres nachala massiva + oldHandler = getvect(0x9); //perekluchaemsya po najatiyu klavishy + setvect(0x9,IntHandler); + Proc1(); + setvect(0x9,oldHandler); + + return 0; +} + +void Proc1(void) +{ + while(1) + printf("Proc1 is working %d\n",current_proc); + } + +void Proc2(void) +{ + while(1) + printf("Proc2 is working %d\n",current_proc); +} + +void Proc3(void) +{ + while(1) + printf("Proc3 is working %d\n",current_proc); +} \ No newline at end of file diff --git a/Opisan b/Opisan new file mode 100755 index 0000000..3e2d465 Binary files /dev/null and b/Opisan differ diff --git a/Protect/PM_INT8.9/DPMI16BI.OVL b/Protect/PM_INT8.9/DPMI16BI.OVL new file mode 100755 index 0000000..69f0e09 Binary files /dev/null and b/Protect/PM_INT8.9/DPMI16BI.OVL differ diff --git a/Protect/PM_INT8.9/DPMILOAD.EXE b/Protect/PM_INT8.9/DPMILOAD.EXE new file mode 100755 index 0000000..17881fa Binary files /dev/null and b/Protect/PM_INT8.9/DPMILOAD.EXE differ diff --git a/Protect/PM_INT8.9/DPMIMEM.DLL b/Protect/PM_INT8.9/DPMIMEM.DLL new file mode 100755 index 0000000..1d24230 Binary files /dev/null and b/Protect/PM_INT8.9/DPMIMEM.DLL differ diff --git a/Protect/PM_INT8.9/ERRMSG b/Protect/PM_INT8.9/ERRMSG new file mode 100755 index 0000000..8c08e17 --- /dev/null +++ b/Protect/PM_INT8.9/ERRMSG @@ -0,0 +1,23 @@ +Компиляция программы для работы в Protected Mode +входной файл pm.asm +___________________ +Создание obj файла... + tasm /m2 pm.asm +Turbo Assembler Version 3.1 Copyright (c) 1988, 1992 Borland International + +Assembling file: pm.asm +Error messages: None +Warning messages: None +Passes: 2 +Remaining memory: 411k + +obj файл успешно создан +___________________ +Режим вывода команд на экран (ECHO): откл +Создание exe файла... +tlink /x /3 pm.obj +Turbo Link Version 5.1 Copyright (c) 1992 Borland International +exe файл успешно создан +___________________ +Компиляция прошла успешно +Создан файл pm.exe diff --git a/Protect/PM_INT8.9/MK.BAT b/Protect/PM_INT8.9/MK.BAT new file mode 100755 index 0000000..40120bd --- /dev/null +++ b/Protect/PM_INT8.9/MK.BAT @@ -0,0 +1,2 @@ +@del errmsg +@mk2.bat %1 errmsg diff --git a/Protect/PM_INT8.9/MK2.BAT b/Protect/PM_INT8.9/MK2.BAT new file mode 100755 index 0000000..f942bdb --- /dev/null +++ b/Protect/PM_INT8.9/MK2.BAT @@ -0,0 +1,43 @@ +@ECHO OFF +ECHO Компиляция программы для работы в Protected Mode >> %2 +ECHO входной файл %1.asm >> %2 +ECHO ___________________ >> %2 + +ECHO Создание obj файла... >> %2 +ECHO tasm /m2 %1.asm >> %2 +tasm /m2 %1.asm >> %2 >> %2 +if errorlevel = 1 goto asmerror +ECHO obj файл успешно создан >> %2 +ECHO ___________________ >> %2 +ECHO >> %2 +ECHO Создание exe файла... >> %2 +ECHO tlink /x /3 %1.obj >> %2 +tlink /x /3 %1.obj >> %2 +if errorlevel = 1 goto exeerror +ECHO exe файл успешно создан >> %2 +goto okend + +:exeerror +ECHO ___________________ >> %2 +ECHO Ошибка создания exe файла, возможно файл >> %2 +ECHO %1.obj создан с ошибками >> %2 +goto errorend + +:asmerror +ECHO Ошибка создания obj файла, возможно в файле >> %2 +ECHO %1.asm обнаружены ошибки >> %2 +goto errorend + +:errorend +ECHO ___________________ >> %2 +ECHO В процессе компиляции обнаружены ошибки, >> %2 +ECHO создание запускаемого(exe) файла невозможно. >> %2 +goto end + +:okend +ECHO ___________________ >> %2 +ECHO Компиляция прошла успешно >> %2 +ECHO Создан файл %1.exe >> %2 + +:end +@type %2 \ No newline at end of file diff --git a/Protect/PM_INT8.9/MKPM.BAT b/Protect/PM_INT8.9/MKPM.BAT new file mode 100755 index 0000000..930f2e7 --- /dev/null +++ b/Protect/PM_INT8.9/MKPM.BAT @@ -0,0 +1 @@ +@mk.bat pm \ No newline at end of file diff --git a/Protect/PM_INT8.9/NOSOUND.EXE b/Protect/PM_INT8.9/NOSOUND.EXE new file mode 100755 index 0000000..fe2578c Binary files /dev/null and b/Protect/PM_INT8.9/NOSOUND.EXE differ diff --git a/Protect/PM_INT8.9/PM.ASM b/Protect/PM_INT8.9/PM.ASM new file mode 100755 index 0000000..c141c87 --- /dev/null +++ b/Protect/PM_INT8.9/PM.ASM @@ -0,0 +1,446 @@ +; Работа студента группы 2084/3 +; Макаренко Антона +; по курсу ЦВМ + +; Программа, производит переход в Protrcted Mode, +; перепрограмирует контроллер прерываний и производит +; перехват прерывания от клавиатуры. + +; Макрос преобразования смещения из 32-х битного сегмента в 16-битную переменную +so equ small offset + +; Макрос задержки. На входе - значение переменной задержки (в мкс). +delay macro time + local ext,iter + push ecx + mov ecx,time +ext: push ecx + mov cx,5000 ;это значение можно поменять, исходя из производительности процессора. +iter: loop iter + pop ecx + loop ext + pop ecx + endm + +.386p + +; Сегмент Real Mode, 16 бит +RM_seg segment para public "CODE" use16 + assume cs: RM_seg, ds: PM_seg, ss: Stack_seg +start: +; Очистить экран + mov ax, 3 + int 10h +; Подготовить сегментные регистры + push PM_seg + pop ds +; Проверить режим (PM или нет) + mov eax, cr0 + test al, 1 + jz no_V86 +; Если уже в PM - сообщить об ошибке и выйти + mov dx, so v86_msg +err_exit: + mov ah, 9 + int 21h + mov ah, 4Ch + int 21h +; Проверить на присутствие Windows +no_V86: + mov ax, 1600h + int 2Fh + test al, al + jz no_Windows +; Если под Wondows - сообщить и выйти + mov dx, so win_msg + jmp short err_exit +; ***************************************** +; Все впорядке, начать выполнение программы +no_Windows: +; Вычислить базы для всех используемых дескрипторов сегментов + xor eax, eax + mov ax, RM_seg ; Базой 16bitCS будет RM_seg + shl eax, 4 + mov word ptr GDT_16bitCS+2, ax ; биты 15-0 + shr eax, 16 + mov byte ptr GDT_16bitCS+4, al ; биты 23-16 + mov ax, PM_seg + shl eax, 4 + mov word ptr GDT_32bitCS+2, ax ; Базой всех 32bit* будет + mov word ptr GDT_32bitSS+2, ax ; PM_seg + mov word ptr GDT_32bitDS+2, ax + shr eax, 16 + mov byte ptr GDT_32bitCS+4, al + mov byte ptr GDT_32bitSS+4, al + mov byte ptr GDT_32bitDS+4, al +; Вычислить линейный адрес GDT + xor eax, eax + mov ax, PM_seg + shl eax, 4 + push eax + add eax, offset GDT + mov dword ptr gdtr+2, eax +; Загрузить GDT + lgdt fword ptr gdtr +; Вычислить линейный адрес IDT + pop eax + add eax, offset IDT + mov dword ptr idtr+2, eax +; Загрузить IDT + lidt fword ptr idtr +; Т.к. собираемся работать с 32-х битной памятью - открыть A20 + in al, 70h + or al, 2 + out 92h, al +; Отключить прерывания + cli +; Отключить немаскируемые прерывания (NMI) + in al, 70h + or al, 80h + out 70h, al +; Перейти в защищенный режим + mov eax, cr0 + or al, 1 + mov cr0, eax +; Загрузить SEL_32bitCS в CS + db 66h ; Префикс преобразования разрядности + db 0EAh ; Дальний переход + dd offset PM_entry + dw Sel_32bitCS +RM_return: +; Перейти в Real Mode + mov eax, cr0 + and al, 0FEh + mov cr0, eax +; Сбросить очередь и загрузить CS реальным числом + db 0EAh + dw $+4 + dw RM_seg +; Установить регистры для работы в реальном режиме + mov ax, PM_seg + mov ds, ax + mov es, ax + mov ax, Stack_seg + mov bx, stack_l + mov ss, ax + mov sp, bx +; Загрузить IDTR для RM + mov ax, PM_seg + mov ds, ax + lidt fword ptr idtr_real +; Разрешить NMI + in al, 70h + and al, 07Fh + out 70h, al +; Разрешить прерывания + sti +; и выйти + mov ah, 4Ch + int 21h +RM_seg ends + +; 32-х битный сегмент +PM_seg segment para "CODE" use32 + assume cs: PM_seg +; Таблица GDT и IDT д.б. выровнены, поэтому размещаются в начале сегмента +GDT label byte + db 8 dup(0) +; 32-x битный 4-х Гб сегмент с базой =0 +GTD_flatDS db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 +; 16-и битный 64-х Кб сегмент кода с базой RM_seg +GDT_16bitCS db 0FFh,0FFh,0,0,0,10011010b,0,0 +; 32-x битный 4-х Гб сегмент кода с базой PM_seg +GDT_32bitCS db 0FFh,0FFh,0,0,0,10011010b,11001111b,0 +; 32-x битный 4-х Гб сегмент данных с базой PM_seg +GDT_32bitDS db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 +; 32-x битный 4-х Гб сегмент данных с базой Stack_seg +GDT_32bitSS db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 +gdt_size = $-GDT +gdtr dw gdt_size-1 ; Предел GDT + dd ? ; Линейный адрес GDT +; Названия селекторов +SEL_flatDS equ 001000b +SEL_16bitCS equ 010000b +SEL_32bitCS equ 011000b +SEL_32bitDS equ 100000b +SEL_32bitSS equ 101000b + +; Таблица дескрипторов прерываний IDT +IDT label byte +; Все дескрипторы имеют тип 0Eh - 32-х битный шлюз прерывания +; INT 00-07 + dw 8 dup(so int_handler, SEL_32bitCS, 8E00h,0) +; INT 08(irq0) +; dw so irq0_7_handler,SEL_32bitCS,8E00h,0 + dw so timer_handler,SEL_32bitCS,8E00h,0 +; INT 09(irq1) + dw so irq1_handler,SEL_32bitCS,8E00h,0 +; INT 0Ah-0Fh (IRQ2-IRQ8) + dw 6 dup(so irq0_7_handler,SEL_32bitCS,8E00h,0) +; INT 10h-6Fh + dw 97 dup(so int_handler,SEL_32bitCS,8E00h,0) +; INT 70h-78h (IRQ8-IRQ15) + dw 8 dup(so irq8_15_handler,SEL_32bitCS,8E00h,0) +; INT 79h-FFh + dw 135 dup(so int_handler,SEL_32bitCS,8E00h,0) +idt_size = $-IDT +idtr dw idt_size-1 ; Предел IDT + dd ? ; Линейный адрес начала IDT +; Содержимое регистра IDTR в реальном режиме +idtr_real dw 3FFh,0,0 + +; Сообщения об ошибках при старте +v86_msg db "Процессор в режиме v86 - нельзя переключиться в PM$" +win_msg db "Программа на может бать запущена из под Windows$" + +; Таблица для перевода OE скан-кодов в ASCII +scan2ascii db 0,1Bh,'1','2','3','4','5','6','7','8','9','0','-','=',8 + db 0,'Q','W','E','R','T','Y','U','I','O','P','[',']',0 + DB 0,'A','S','D','F','G','H','J','K','L',';',27h,'`',0 ; LShift + db '\','Z','X','C','V','B','N','M',',','.','/',0 ; RShift + db '0','0',' ' ; SP +screen_addr dd 0 ; Текущая позиция на экране +N dd 64 ; Индекс в массиве MUS +NM dd 1 ; Счетчик длительности +; Массив пар звучания: 1-е число - частота, 2-е - длительность +MUS dw 1218,10, 767,10, 813,10, 912,10, 966,10, 912,30 + dw 1218,10, 609,10, 678,10, 767,10, 813,10, 767,30 + dw 912,10, 574,15, 609,5, 678,15, 767,5, 813,5 + dw 767,5, 678,20, 574,10, 609,10, 678,10, 767,10 + dw 678,10, 813,30, 1218,10, 767,10, 813,10, 912,10 + dw 966,10, 912,30, 1218,10, 609,10, 678,10, 767,10 + dw 813,10, 767,30, 912,10, 574,15, 609,5, 678,15 + dw 767,5, 813,5, 767,5, 678,20, 574,10, 609,10 + dw 678,10, 767,10, 678,10, 813,30, 0,2, 609,10 + dw 609,10, 912,10, 724,10, 609,10, 609,5, 678,5 + dw 724,5, 678,5, 574,15, 678,5, 678,10, 1024,10 + dw 813,10, 678,10, 678,5, 767,5, 813,5, 724,5 + dw 609,20, 678,5, 609,5, 574,5, 456,5, 342,5 + dw 384,5, 406,5, 456,5, 456,20, 483,20, 678,5 + dw 609,5, 574,5, 456,5, 342,5, 384,5, 406,5 + dw 456,5, 456,10, 483,10, 456,20, 0,2, 456,5 + dw 456,10, 483,10, 456,20, 0,30 +;MC = ($-MUS)/4; Music Count - количество нот +MC = 100 + +; Точка входа в 32-х битный защищенный режим +PM_entry: +; Установить 32-х битный стек и другие регистры + mov ax, SEL_flatDS + mov ds, ax + mov es, ax + mov ax, SEL_32bitSS + mov ebx, stack_l + mov ss, ax + mov esp, ebx +; Разрешить прерывания + sti +; и войти в вечный цикл + jmp short $ + +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +;! Обработчики прерываний ! +;! Многие не корректны - нельзя допускать ошибок ! +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +; Обработчик обычного прерывания +int_handler: + iretd +; Обработчик аппаратного прерывания IRQ0-IRQ7 +irq0_7_handler: + push eax + mov al, 20h + out 20h, al + pop eax + iretd +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +; Обработчик прерывания от таймера (int8) ! +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +timer_handler: +; Сохранить регистры + push eax + push ebx + push es + push ds + + mov bx, SEL_32bitDS ; Загрузить сегмент данных + mov ds, bx + + dec NM ; Текущее время звучания + mov eax, NM ; Если не истекло, + cmp eax, 0 + jnz contin_mus ; то ничего не делать, иначе + ; Выключить звук + in al, 61h + and al, 0FCh + out 61h, al + delay 1 ; Пауза + ; Выбрать высоту следущеюй ноты + inc N ; Увеличить на ед. + mov eax, N ; Текущая позиция + mov ebx, 4 ; ! Размер пары в байтах + mul ebx ; Смещение пары, относительно начала массива + add eax, offset MUS ; Адрес + push eax ; сохранить +; xor eax, eax + mov ax, [eax] ; В AX - частота + ; Начать звучание + mov ebx, eax ; Подготовка + shr ebx, 8 ; параметров для + and ax, 00FFh ; записи в порты + push eax + mov ax, 0B6h ; \ + out 43h, ax ; _\outportb(0x43, 0xB6) + pop eax ; EAX = Частота & 0x00FF + out 42h, ax + xchg ax, bx ; ax = Частота >> 8 + out 42h, ax + in al, 61h + or al, 03h + out 61h, al + ; Выбрать длительность + pop ebx ; EBX = адрес текущей пары + xor eax, eax + mov ax, word ptr [ebx+2] ; EAX = Длительность + mov NM, eax + + cmp N, MC ; Если не в конце мелодии, + jb contin_mus ; то ничего, + mov N, 0 ; иначе - в начало массива + +contin_mus: +; mov NM, eax ; Сохранить текущее время звучания +; Снять с контроллера + mov al, 20h + out 20h, al +; Восстановить регистры, выйти + pop ds + pop es + pop ebx + pop eax + iretd +; Обработчик аппаратного прерывания IRQ8-IRQ15 +irq8_15_handler: + push eax + mov al, 20h + out 0A1h, al + pop eax + iretd +; Обработчик IRQ1 - прерывание от клавиатуры +irq1_handler: + push eax ; Это аппаратное прерывание - + push ebx ; сохранить регистры + push edx + push es + push ds + in al, 60h ; Прочитать скан-код нажатой клавиши +; cmp al, 0Eh ; Если он больше, чем обслуживаемый + cmp al, 39h ; Если он больше, чем обслуживаемый + ja skip_translate ; нами, - не обрабатывать + cmp al, 1 ; Если это ESC, + je esc_pressed ; выйти в реальный режим + mov bx, SEL_32bitDS ; Иначе: + mov ds, bx ; DS:EBX - таблица для перевода + mov ebx, offset scan2ascii ; скан-кода в ASCII + xlatb ; Преобразовать + mov bx, SEL_flatDS + mov es, bx ; ES:EBX - адрес текущей + mov ebx, screen_addr ; Позиции на экране + cmp al, 8 ; Если нажата BkSpace + je bs_pressed ; на соответствующий обработчик + cmp al, 0 ; + je skip_translate ; + mov es:[ebx+0B8000h], al ; иначе послать символ на экран + add dword ptr screen_addr, 2; Увеличить адрес позиции на 2 + ; Сменить позицию курсора + mov ebx, screen_addr + shr ebx, 1 +;! mov eax, ebx +;! mov ebx, 2 +;!!! div ebx +; mov ebx, eax +; mov ebx, screen_addr +; inc ebx + xor edx, edx + xor eax, eax + mov dx, 03D4h ; Регистры контроллера CRT + mov al, 0Fh ; обращение к регистру младшего байта + mov ah, bl + out dx, ax + mov al, 0Eh ; к рег. старшего байта + mov ah, bh + out dx, ax + jmp short skip_translate +bs_pressed: ; Нажат BkSpace: + mov al,' ' ; Вывести пробел + sub ebx, 2 ; в позиции предыдущего символа + mov es:[ebx+0B8000h], al + mov screen_addr, ebx ; и сохранить адрес передыд символа, + ; как текущий + ; Сменить позицию курсора + shr ebx, 1 +;! mov eax, ebx +;! mov ebx, 2 +;!!! div ebx +; mov ebx, eax +; mov ebx, screen_addr +; inc ebx + xor edx, edx + xor eax, eax + mov dx, 03D4h ; Регистры контроллера CRT + mov al, 0Fh ; обращение к регистру младшего байта + mov ah, bl + out dx, ax + mov al, 0Eh ; к рег. старшего байта + mov ah, bh + out dx, ax + +skip_translate: +; Разрешить работу клавиатуры + in al, 61h + or al, 80h + out 61h, al +; Послать EOI контроллеру прерываний + mov al, 20h + out 20h, al +; Восстановить регистры и выйти + pop ds + pop es + pop edx + pop ebx + pop eax + iretd + +; ******************* +; Нажата ESC +esc_pressed: +; Разрешить работу клавиатуры, послать EOI и восстановить регистры + in al, 61h + or al, 80h + out 61h, al + mov al, 20h + out 20h, al + cli +; Отключить звук + in al, 61h + and al, 0FCh + out 61h, al + pop ds + pop es + pop edx + pop ebx + pop eax +; Вернуться в реальный режим + + db 0EAh + dd offset RM_return + dw SEL_16bitCS +PM_seg ends + +; Сегмент стека, используется как 16-битный в 16-битной части программы и как +; 32-х битный (через селектор SEL_32bitSS) в 32-х битной части +Stack_seg segment para stack "STACK" +stack_start db 100h dup(?) +stack_l = $-stack_start ; Длина стека для инициализации ESP +Stack_seg ends + end start diff --git a/Protect/PM_INT8.9/PM.EXE b/Protect/PM_INT8.9/PM.EXE new file mode 100755 index 0000000..d4692bb Binary files /dev/null and b/Protect/PM_INT8.9/PM.EXE differ diff --git a/Protect/PM_INT8.9/PM.OBJ b/Protect/PM_INT8.9/PM.OBJ new file mode 100755 index 0000000..9dbfa1f Binary files /dev/null and b/Protect/PM_INT8.9/PM.OBJ differ diff --git a/Protect/PM_INT8.9/PM1.ASM b/Protect/PM_INT8.9/PM1.ASM new file mode 100755 index 0000000..361d888 --- /dev/null +++ b/Protect/PM_INT8.9/PM1.ASM @@ -0,0 +1,293 @@ +; Работа студента группы 2084/3 +; Макаренко Антона +; по курсу ЦВМ + +; Программа, производит переход в Protrcted Mode, +; перепрограмирует контроллер прерываний и производит +; перехват прерывания от клавиатуры. + +; Макрос преобразования смещения из 32-х битного сегмента в 16-битную переменную +so equ small offset + +.386p + +; Сегмент Real Mode, 16 бит +RM_seg segment para public "CODE" use16 + assume cs: RM_seg, ds: PM_seg, ss: Stack_seg +start: +; Очистить экран + mov ax, 3 + int 10h +; Подготовить сегментные регистры + push PM_seg + pop ds +; Проверить режим (PM или нет) + mov eax, cr0 + test al, 1 + jz no_V86 +; Если уже в PM - сообщить об ошибке и выйти + mov dx, so v86_msg +err_exit: + mov ah, 9 + int 21h + mov ah, 4Ch + int 21h +; Проверить на присутствие Windows +no_V86: + mov ax, 1600h + int 2Fh + test al, al + jz no_Windows +; Если под Wondows - сообщить и выйти + mov dx, so win_msg + jmp short err_exit +; ***************************************** +; Все впорядке, начать выполнение программы +no_Windows: +; Вычислить базы для всех используемых дескрипторов сегментов + xor eax, eax + mov ax, RM_seg ; Базой 16bitCS будет RM_seg + shl eax, 4 + mov word ptr GDT_16bitCS+2, ax ; биты 15-0 + shr eax, 16 + mov byte ptr GDT_16bitCS+4, al ; биты 23-16 + mov ax, PM_seg + shl eax, 4 + mov word ptr GDT_32bitCS+2, ax ; Базой всех 32bit* будет + mov word ptr GDT_32bitSS+2, ax ; PM_seg + mov word ptr GDT_32bitDS+2, ax + shr eax, 16 + mov byte ptr GDT_32bitCS+4, al + mov byte ptr GDT_32bitSS+4, al + mov byte ptr GDT_32bitDS+4, al +; Вычислить линейный адрес GDT + xor eax, eax + mov ax, PM_seg + shl eax, 4 + push eax + add eax, offset GDT + mov dword ptr gdtr+2, eax +; Загрузить GDT + lgdt fword ptr gdtr +; Вычислить линейный адрес IDT + pop eax + add eax, offset IDT + mov dword ptr idtr+2, eax +; Загрузить IDT + lidt fword ptr idtr +; Т.к. собираемся работать с 32-х битной памятью - открыть A20 + in al, 70h + or al, 2 + out 92h, al +; Отключить прерывания + cli +; Отключить немаскируемые прерывания (NMI) + in al, 70h + or al, 80h + out 70h, al +; Перейти в защищенный режим + mov eax, cr0 + or al, 1 + mov cr0, eax +; Загрузить SEL_32bitCS в CS + db 66h ; Префикс преобразования разрядности + db 0EAh ; Дальний переход + dd offset PM_entry + dw Sel_32bitCS +RM_return: +; Перейти в Real Mode + mov eax, cr0 + and al, 0FEh + mov cr0, eax +; Сбросить очередь и загрузить CS реальным числом + db 0EAh + dw $+4 + dw RM_seg +; Установить регистры для работы в реальном режиме + mov ax, PM_seg + mov ds, ax + mov es, ax + mov ax, Stack_seg + mov bx, stack_l + mov ss, ax + mov sp, bx +; Загрузить IDTR для RM + mov ax, PM_seg + mov ds, ax + lidt fword ptr idtr_real +; Разрешить NMI + in al, 70h + and al, 07Fh + out 70h, al +; Разрешить прерывания + sti +; и выйти + mov ah, 4Ch + int 21h +RM_seg ends + +; 32-х битный сегмент +PM_seg segment para "CODE" use32 + assume cs: PM_seg +; Таблица GDT и IDT д.б. выровнены, поэтому размещаются в начале сегмента +GDT label byte + db 8 dup(0) +; 32-x битный 4-х Гб сегмент с базой =0 +GTD_flatDS db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 +; 16-и битный 64-х Кб сегмент кода с базой RM_seg +GDT_16bitCS db 0FFh,0FFh,0,0,0,10011010b,0,0 +; 32-x битный 4-х Гб сегмент кода с базой PM_seg +GDT_32bitCS db 0FFh,0FFh,0,0,0,10011010b,11001111b,0 +; 32-x битный 4-х Гб сегмент данных с базой PM_seg +GDT_32bitDS db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 +; 32-x битный 4-х Гб сегмент данных с базой Stack_seg +GDT_32bitSS db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 +gdt_size = $-GDT +gdtr dw gdt_size-1 ; Предел GDT + dd ? ; Линейный адрес GDT +; Названия селекторов +SEL_flatDS equ 001000b +SEL_16bitCS equ 010000b +SEL_32bitCS equ 011000b +SEL_32bitDS equ 100000b +SEL_32bitSS equ 101000b + +; Таблица дескрипторов прерываний IDT +IDT label byte +; Все дескрипторы имеют тип 0Eh - 32-х битный шлюз прерывания +; INT 00-07 + dw 8 dup(so int_handler, SEL_32bitCS, 8E00h,0) +; INT 08(irq0) + dw so irq0_7_handler,SEL_32bitCS,8E00h,0 +; INT 09(irq1) + dw so irq1_handler,SEL_32bitCS,8E00h,0 +; INT 0Ah-0Fh (IRQ2-IRQ8) + dw 6 dup(so irq0_7_handler,SEL_32bitCS,8E00h,0) +; INT 10h-6Fh + dw 97 dup(so int_handler,SEL_32bitCS,8E00h,0) +; INT 70h-78h (IRQ8-IRQ15) + dw 8 dup(so irq8_15_handler,SEL_32bitCS,8E00h,0) +; INT 79h-FFh + dw 135 dup(so int_handler,SEL_32bitCS,8E00h,0) +idt_size = $-IDT +idtr dw idt_size-1 ; Предел IDT + dd ? ; Линейный адрес начала IDT +; Содержимое регистра IDTR в реальном режиме +idtr_real dw 3FFh,0,0 + +; Сообщения об ошибках при старте +v86_msg db "Процессор в режиме v86 - нельзя переключиться в PM$" +win_msg db "Программа на может бать запущена из под Windows$" + +; Таблица для перевода OE скан-кодов в ASCII +scan2ascii db 0,1Bh,'1','2','3','4','5','6','7','8','9','0','-','=',8 +screen_addr dd 0 ; Текущая позиция на экране + +; Точка входа в 32-х битный защищенный режим +PM_entry: +; Установить 32-х битный стек и другие регистры + mov ax, SEL_flatDS + mov ds, ax + mov es, ax + mov ax, SEL_32bitSS + mov ebx, stack_l + mov ss, ax + mov esp, ebx +; Разрешить прерывания + sti +; и войти в вечный цикл + jmp short $ + +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +;! Обработчики прерываний ! +;! Многие не корректны - нельзя допускать ошибок ! +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +; Обработчик обычного прерывания +int_handler: + iretd +; Обработчик аппаратного прерывания IRQ0-IRQ7 +irq0_7_handler: + push eax + mov al, 20h + out 20h, al + pop eax + iretd +; Обработчик аппаратного прерывания IRQ8-IRQ15 +irq8_15_handler: + push eax + mov al, 20h + out 0A1h, al + pop eax + iretd +; Обработчик IRQ1 - прерывание от клавиатуры +irq1_handler: + push eax ; Это аппаратное прерывание - + push ebx ; сохранить регистры + push es + push ds + in al, 60h ; Прочитать скан-код нажатой клавиши + cmp al, 0Eh ; Если он больше, чем обслуживаемый + ja skip_translate ; нами, - не обрабатывать + cmp al, 1 ; Если это ESC, + je esc_pressed ; выйти в реальный режим + mov bx, SEL_32bitDS ; Иначе: + mov ds, bx ; DS:EBX - таблица для перевода + mov ebx, offset scan2ascii ; скан-кода в ASCII + xlatb ; Преобразовать + mov bx, SEL_flatDS + mov es, bx ; ES:EBX - адрес текущей + mov ebx, screen_addr ; Позиции на экране + cmp al, 8 ; Если нажата BkSpace + je bs_pressed ; на соответствующий обработчик + mov es:[ebx+0B8000h], al ; иначе послать символ на экран + add dword ptr screen_addr, 2; Увеличить адрес позиции на 2 + jmp short skip_translate +bs_pressed: ; Нажат BkSpace: + mov al,' ' ; Вывести пробел + sub ebx, 2 ; в позиции предыдущего символа + mov es:[ebx+0B8000h], al + mov screen_addr, ebx ; и сохранить адрес передыд символа, + ; как текущий +skip_translate: +; Разрешить работу клавиатуры + in al, 61h + or al, 80h + out 61h, al +; Послать EOI контроллеру прерываний + mov al, 20h + out 20h, al +; Восстановить регистры и выйти + pop ds + pop es + pop ebx + pop eax + iretd + +; ******************* +; Нажата ESC +esc_pressed: +; Разрешить работу клавиатуры, послать EOI и восстановить регистры + in al, 61h + or al, 80h + out 61h, al + mov al, 20h + out 20h, al + pop ds + pop es + pop ebx + pop eax +; Вернуться в реальный режим + cli + db 0EAh + dd offset RM_return + dw SEL_16bitCS +PM_seg ends + +; Сегмент стека, используется как 16-битный в 16-битной части программы и как +; 32-х битный (через селектор SEL_32bitSS) в 32-х битной части +Stack_seg segment para stack "STACK" +stack_start db 100h dup(?) +stack_l = $-stack_start ; Длина стека для инициализации ESP +Stack_seg ends + end start diff --git a/Protect/PM_INT8.9/PM2.ASM b/Protect/PM_INT8.9/PM2.ASM new file mode 100755 index 0000000..213ec65 --- /dev/null +++ b/Protect/PM_INT8.9/PM2.ASM @@ -0,0 +1,400 @@ +; Работа студента группы 2084/3 +; Макаренко Антона +; по курсу ЦВМ + +; Программа, производит переход в Protrcted Mode, +; перепрограмирует контроллер прерываний и производит +; перехват прерывания от клавиатуры. + +; Макрос преобразования смещения из 32-х битного сегмента в 16-битную переменную +so equ small offset + +; Макрос задержки. На входе - значение переменной задержки (в мкс). +delay macro time + local ext,iter + push ecx + mov ecx,time +ext: push ecx + mov cx,5000 ;это значение можно поменять, исходя из производительности процессора. +iter: loop iter + pop ecx + loop ext + pop ecx + endm + +.386p + +; Сегмент Real Mode, 16 бит +RM_seg segment para public "CODE" use16 + assume cs: RM_seg, ds: PM_seg, ss: Stack_seg +start: +; Очистить экран + mov ax, 3 + int 10h +; Подготовить сегментные регистры + push PM_seg + pop ds +; Проверить режим (PM или нет) + mov eax, cr0 + test al, 1 + jz no_V86 +; Если уже в PM - сообщить об ошибке и выйти + mov dx, so v86_msg +err_exit: + mov ah, 9 + int 21h + mov ah, 4Ch + int 21h +; Проверить на присутствие Windows +no_V86: + mov ax, 1600h + int 2Fh + test al, al + jz no_Windows +; Если под Wondows - сообщить и выйти + mov dx, so win_msg + jmp short err_exit +; ***************************************** +; Все впорядке, начать выполнение программы +no_Windows: +; Вычислить базы для всех используемых дескрипторов сегментов + xor eax, eax + mov ax, RM_seg ; Базой 16bitCS будет RM_seg + shl eax, 4 + mov word ptr GDT_16bitCS+2, ax ; биты 15-0 + shr eax, 16 + mov byte ptr GDT_16bitCS+4, al ; биты 23-16 + mov ax, PM_seg + shl eax, 4 + mov word ptr GDT_32bitCS+2, ax ; Базой всех 32bit* будет + mov word ptr GDT_32bitSS+2, ax ; PM_seg + mov word ptr GDT_32bitDS+2, ax + shr eax, 16 + mov byte ptr GDT_32bitCS+4, al + mov byte ptr GDT_32bitSS+4, al + mov byte ptr GDT_32bitDS+4, al +; Вычислить линейный адрес GDT + xor eax, eax + mov ax, PM_seg + shl eax, 4 + push eax + add eax, offset GDT + mov dword ptr gdtr+2, eax +; Загрузить GDT + lgdt fword ptr gdtr +; Вычислить линейный адрес IDT + pop eax + add eax, offset IDT + mov dword ptr idtr+2, eax +; Загрузить IDT + lidt fword ptr idtr +; Т.к. собираемся работать с 32-х битной памятью - открыть A20 + in al, 70h + or al, 2 + out 92h, al +; Отключить прерывания + cli +; Отключить немаскируемые прерывания (NMI) + in al, 70h + or al, 80h + out 70h, al +; Перейти в защищенный режим + mov eax, cr0 + or al, 1 + mov cr0, eax +; Загрузить SEL_32bitCS в CS + db 66h ; Префикс преобразования разрядности + db 0EAh ; Дальний переход + dd offset PM_entry + dw Sel_32bitCS +RM_return: +; Перейти в Real Mode + mov eax, cr0 + and al, 0FEh + mov cr0, eax +; Сбросить очередь и загрузить CS реальным числом + db 0EAh + dw $+4 + dw RM_seg +; Установить регистры для работы в реальном режиме + mov ax, PM_seg + mov ds, ax + mov es, ax + mov ax, Stack_seg + mov bx, stack_l + mov ss, ax + mov sp, bx +; Загрузить IDTR для RM + mov ax, PM_seg + mov ds, ax + lidt fword ptr idtr_real +; Разрешить NMI + in al, 70h + and al, 07Fh + out 70h, al +; Разрешить прерывания + sti +; и выйти + mov ah, 4Ch + int 21h +RM_seg ends + +; 32-х битный сегмент +PM_seg segment para "CODE" use32 + assume cs: PM_seg +; Таблица GDT и IDT д.б. выровнены, поэтому размещаются в начале сегмента +GDT label byte + db 8 dup(0) +; 32-x битный 4-х Гб сегмент с базой =0 +GTD_flatDS db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 +; 16-и битный 64-х Кб сегмент кода с базой RM_seg +GDT_16bitCS db 0FFh,0FFh,0,0,0,10011010b,0,0 +; 32-x битный 4-х Гб сегмент кода с базой PM_seg +GDT_32bitCS db 0FFh,0FFh,0,0,0,10011010b,11001111b,0 +; 32-x битный 4-х Гб сегмент данных с базой PM_seg +GDT_32bitDS db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 +; 32-x битный 4-х Гб сегмент данных с базой Stack_seg +GDT_32bitSS db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 +gdt_size = $-GDT +gdtr dw gdt_size-1 ; Предел GDT + dd ? ; Линейный адрес GDT +; Названия селекторов +SEL_flatDS equ 001000b +SEL_16bitCS equ 010000b +SEL_32bitCS equ 011000b +SEL_32bitDS equ 100000b +SEL_32bitSS equ 101000b + +; Таблица дескрипторов прерываний IDT +IDT label byte +; Все дескрипторы имеют тип 0Eh - 32-х битный шлюз прерывания +; INT 00-07 + dw 8 dup(so int_handler, SEL_32bitCS, 8E00h,0) +; INT 08(irq0) +; dw so irq0_7_handler,SEL_32bitCS,8E00h,0 + dw so timer_handler,SEL_32bitCS,8E00h,0 +; INT 09(irq1) + dw so irq1_handler,SEL_32bitCS,8E00h,0 +; INT 0Ah-0Fh (IRQ2-IRQ8) + dw 6 dup(so irq0_7_handler,SEL_32bitCS,8E00h,0) +; INT 10h-6Fh + dw 97 dup(so int_handler,SEL_32bitCS,8E00h,0) +; INT 70h-78h (IRQ8-IRQ15) + dw 8 dup(so irq8_15_handler,SEL_32bitCS,8E00h,0) +; INT 79h-FFh + dw 135 dup(so int_handler,SEL_32bitCS,8E00h,0) +idt_size = $-IDT +idtr dw idt_size-1 ; Предел IDT + dd ? ; Линейный адрес начала IDT +; Содержимое регистра IDTR в реальном режиме +idtr_real dw 3FFh,0,0 + +; Сообщения об ошибках при старте +v86_msg db "Процессор в режиме v86 - нельзя переключиться в PM$" +win_msg db "Программа на может бать запущена из под Windows$" + +; Таблица для перевода OE скан-кодов в ASCII +scan2ascii db 0,1Bh,'1','2','3','4','5','6','7','8','9','0','-','=',8 +screen_addr dd 0 ; Текущая позиция на экране +N dd 64 ; Индекс в массиве MUS +NM dd 1 ; Счетчик длительности +; Массив пар звучания: 1-е число - частота, 2-е - длительность +MUS dw 1218,10, 767,10, 813,10, 912,10, 966,10, 912,30 + dw 1218,10, 609,10, 678,10, 767,10, 813,10, 767,30 + dw 912,10, 574,15, 609,5, 678,15, 767,5, 813,5 + dw 767,5, 678,20, 574,10, 609,10, 678,10, 767,10 + dw 678,10, 813,30, 1218,10, 767,10, 813,10, 912,10 + dw 966,10, 912,30, 1218,10, 609,10, 678,10, 767,10 + dw 813,10, 767,30, 912,10, 574,15, 609,5, 678,15 + dw 767,5, 813,5, 767,5, 678,20, 574,10, 609,10 + dw 678,10, 767,10, 678,10, 813,30, 0,2, 609,10 + dw 609,10, 912,10, 724,10, 609,10, 609,5, 678,5 + dw 724,5, 678,5, 574,15, 678,5, 678,10, 1024,10 + dw 813,10, 678,10, 678,5, 767,5, 813,5, 724,5 + dw 609,20, 678,5, 609,5, 574,5, 456,5, 342,5 + dw 384,5, 406,5, 456,5, 456,20, 483,20, 678,5 + dw 609,5, 574,5, 456,5, 342,5, 384,5, 406,5 + dw 456,5, 456,10, 483,10, 456,20, 0,2, 456,5 + dw 456,10, 483,10, 456,20, 0,30 +;MC = ($-MUS)/4; Music Count - количество нот +MC = 100 + +; Точка входа в 32-х битный защищенный режим +PM_entry: +; Установить 32-х битный стек и другие регистры + mov ax, SEL_flatDS + mov ds, ax + mov es, ax + mov ax, SEL_32bitSS + mov ebx, stack_l + mov ss, ax + mov esp, ebx +; Разрешить прерывания + sti +; и войти в вечный цикл + jmp short $ + +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +;! Обработчики прерываний ! +;! Многие не корректны - нельзя допускать ошибок ! +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +; Обработчик обычного прерывания +int_handler: + iretd +; Обработчик аппаратного прерывания IRQ0-IRQ7 +irq0_7_handler: + push eax + mov al, 20h + out 20h, al + pop eax + iretd +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +; Обработчик прерывания от таймера (int8) ! +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +timer_handler: +; Сохранить регистры + push eax + push ebx + push es + push ds + + mov bx, SEL_32bitDS ; Загрузить сегмент данных + mov ds, bx + + dec NM ; Текущее время звучания + mov eax, NM ; Если не истекло, + cmp eax, 0 + jnz contin_mus ; то ничего не делать, иначе + ; Выключить звук + in al, 61h + and al, 0FCh + out 61h, al + delay 1 ; Пауза + ; Выбрать высоту следущеюй ноты + inc N ; Увеличить на ед. + mov eax, N ; Текущая позиция + mov ebx, 4 ; ! Размер пары в байтах + mul ebx ; Смещение пары, относительно начала массива + add eax, offset MUS ; Адрес + push eax ; сохранить +; xor eax, eax + mov ax, [eax] ; В AX - частота + ; Начать звучание + mov ebx, eax ; Подготовка + shr ebx, 8 ; параметров для + and ax, 00FFh ; записи в порты + push eax + mov ax, 0B6h ; \ + out 43h, ax ; _\outportb(0x43, 0xB6) + pop eax ; EAX = Частота & 0x00FF + out 42h, ax + xchg ax, bx ; ax = Частота >> 8 + out 42h, ax + in al, 61h + or al, 03h + out 61h, al + ; Выбрать длительность + pop ebx ; EBX = адрес текущей пары + xor eax, eax + mov ax, word ptr [ebx+2] ; EAX = Длительность + mov NM, eax + + cmp N, MC ; Если не в конце мелодии, + jb contin_mus ; то ничего, + mov N, 0 ; иначе - в начало массива + +contin_mus: +; mov NM, eax ; Сохранить текущее время звучания +; Снять с контроллера + mov al, 20h + out 20h, al +; Восстановить регистры, выйти + pop ds + pop es + pop ebx + pop eax + iretd +; Обработчик аппаратного прерывания IRQ8-IRQ15 +irq8_15_handler: + push eax + mov al, 20h + out 0A1h, al + pop eax + iretd +; Обработчик IRQ1 - прерывание от клавиатуры +irq1_handler: + push eax ; Это аппаратное прерывание - + push ebx ; сохранить регистры + push es + push ds + in al, 60h ; Прочитать скан-код нажатой клавиши + cmp al, 0Eh ; Если он больше, чем обслуживаемый + ja skip_translate ; нами, - не обрабатывать + cmp al, 1 ; Если это ESC, + je esc_pressed ; выйти в реальный режим + mov bx, SEL_32bitDS ; Иначе: + mov ds, bx ; DS:EBX - таблица для перевода + mov ebx, offset scan2ascii ; скан-кода в ASCII + xlatb ; Преобразовать + mov bx, SEL_flatDS + mov es, bx ; ES:EBX - адрес текущей + mov ebx, screen_addr ; Позиции на экране + cmp al, 8 ; Если нажата BkSpace + je bs_pressed ; на соответствующий обработчик + mov es:[ebx+0B8000h], al ; иначе послать символ на экран + add dword ptr screen_addr, 2; Увеличить адрес позиции на 2 + jmp short skip_translate +bs_pressed: ; Нажат BkSpace: + mov al,' ' ; Вывести пробел + sub ebx, 2 ; в позиции предыдущего символа + mov es:[ebx+0B8000h], al + mov screen_addr, ebx ; и сохранить адрес передыд символа, + ; как текущий +skip_translate: +; Разрешить работу клавиатуры + in al, 61h + or al, 80h + out 61h, al +; Послать EOI контроллеру прерываний + mov al, 20h + out 20h, al +; Восстановить регистры и выйти + pop ds + pop es + pop ebx + pop eax + iretd + +; ******************* +; Нажата ESC +esc_pressed: +; Разрешить работу клавиатуры, послать EOI и восстановить регистры + in al, 61h + or al, 80h + out 61h, al + mov al, 20h + out 20h, al + cli +; Отключить звук + in al, 61h + and al, 0FCh + out 61h, al + pop ds + pop es + pop ebx + pop eax +; Вернуться в реальный режим + + db 0EAh + dd offset RM_return + dw SEL_16bitCS +PM_seg ends + +; Сегмент стека, используется как 16-битный в 16-битной части программы и как +; 32-х битный (через селектор SEL_32bitSS) в 32-х битной части +Stack_seg segment para stack "STACK" +stack_start db 100h dup(?) +stack_l = $-stack_start ; Длина стека для инициализации ESP +Stack_seg ends + end start diff --git a/Protect/PM_INT8.9/PM3.ASM b/Protect/PM_INT8.9/PM3.ASM new file mode 100755 index 0000000..8901d77 --- /dev/null +++ b/Protect/PM_INT8.9/PM3.ASM @@ -0,0 +1,446 @@ +; Работа студента группы 2084/3 +; Макаренко Антона +; по курсу ЦВМ + +; Программа, производит переход в Protrcted Mode, +; перепрограмирует контроллер прерываний и производит +; перехват прерывания от клавиатуры. + +; Макрос преобразования смещения из 32-х битного сегмента в 16-битную переменную +so equ small offset + +; Макрос задержки. На входе - значение переменной задержки (в мкс). +delay macro time + local ext,iter + push ecx + mov ecx,time +ext: push ecx + mov cx,5000 ;это значение можно поменять, исходя из производительности процессора. +iter: loop iter + pop ecx + loop ext + pop ecx + endm + +.386p + +; Сегмент Real Mode, 16 бит +RM_seg segment para public "CODE" use16 + assume cs: RM_seg, ds: PM_seg, ss: Stack_seg +start: +; Очистить экран + mov ax, 3 + int 10h +; Подготовить сегментные регистры + push PM_seg + pop ds +; Проверить режим (PM или нет) + mov eax, cr0 + test al, 1 + jz no_V86 +; Если уже в PM - сообщить об ошибке и выйти + mov dx, so v86_msg +err_exit: + mov ah, 9 + int 21h + mov ah, 4Ch + int 21h +; Проверить на присутствие Windows +no_V86: + mov ax, 1600h + int 2Fh + test al, al + jz no_Windows +; Если под Wondows - сообщить и выйти + mov dx, so win_msg + jmp short err_exit +; ***************************************** +; Все впорядке, начать выполнение программы +no_Windows: +; Вычислить базы для всех используемых дескрипторов сегментов + xor eax, eax + mov ax, RM_seg ; Базой 16bitCS будет RM_seg + shl eax, 4 + mov word ptr GDT_16bitCS+2, ax ; биты 15-0 + shr eax, 16 + mov byte ptr GDT_16bitCS+4, al ; биты 23-16 + mov ax, PM_seg + shl eax, 4 + mov word ptr GDT_32bitCS+2, ax ; Базой всех 32bit* будет + mov word ptr GDT_32bitSS+2, ax ; PM_seg + mov word ptr GDT_32bitDS+2, ax + shr eax, 16 + mov byte ptr GDT_32bitCS+4, al + mov byte ptr GDT_32bitSS+4, al + mov byte ptr GDT_32bitDS+4, al +; Вычислить линейный адрес GDT + xor eax, eax + mov ax, PM_seg + shl eax, 4 + push eax + add eax, offset GDT + mov dword ptr gdtr+2, eax +; Загрузить GDT + lgdt fword ptr gdtr +; Вычислить линейный адрес IDT + pop eax + add eax, offset IDT + mov dword ptr idtr+2, eax +; Загрузить IDT + lidt fword ptr idtr +; Т.к. собираемся работать с 32-х битной памятью - открыть A20 + in al, 70h + or al, 2 + out 92h, al +; Отключить прерывания + cli +; Отключить немаскируемые прерывания (NMI) + in al, 70h + or al, 80h + out 70h, al +; Перейти в защищенный режим + mov eax, cr0 + or al, 1 + mov cr0, eax +; Загрузить SEL_32bitCS в CS + db 66h ; Префикс преобразования разрядности + db 0EAh ; Дальний переход + dd offset PM_entry + dw Sel_32bitCS +RM_return: +; Перейти в Real Mode + mov eax, cr0 + and al, 0FEh + mov cr0, eax +; Сбросить очередь и загрузить CS реальным числом + db 0EAh + dw $+4 + dw RM_seg +; Установить регистры для работы в реальном режиме + mov ax, PM_seg + mov ds, ax + mov es, ax + mov ax, Stack_seg + mov bx, stack_l + mov ss, ax + mov sp, bx +; Загрузить IDTR для RM + mov ax, PM_seg + mov ds, ax + lidt fword ptr idtr_real +; Разрешить NMI + in al, 70h + and al, 07Fh + out 70h, al +; Разрешить прерывания + sti +; и выйти + mov ah, 4Ch + int 21h +RM_seg ends + +; 32-х битный сегмент +PM_seg segment para "CODE" use32 + assume cs: PM_seg +; Таблица GDT и IDT д.б. выровнены, поэтому размещаются в начале сегмента +GDT label byte + db 8 dup(0) +; 32-x битный 4-х Гб сегмент с базой =0 +GTD_flatDS db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 +; 16-и битный 64-х Кб сегмент кода с базой RM_seg +GDT_16bitCS db 0FFh,0FFh,0,0,0,10011010b,0,0 +; 32-x битный 4-х Гб сегмент кода с базой PM_seg +GDT_32bitCS db 0FFh,0FFh,0,0,0,10011010b,11001111b,0 +; 32-x битный 4-х Гб сегмент данных с базой PM_seg +GDT_32bitDS db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 +; 32-x битный 4-х Гб сегмент данных с базой Stack_seg +GDT_32bitSS db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 +gdt_size = $-GDT +gdtr dw gdt_size-1 ; Предел GDT + dd ? ; Линейный адрес GDT +; Названия селекторов +SEL_flatDS equ 001000b +SEL_16bitCS equ 010000b +SEL_32bitCS equ 011000b +SEL_32bitDS equ 100000b +SEL_32bitSS equ 101000b + +; Таблица дескрипторов прерываний IDT +IDT label byte +; Все дескрипторы имеют тип 0Eh - 32-х битный шлюз прерывания +; INT 00-07 + dw 8 dup(so int_handler, SEL_32bitCS, 8E00h,0) +; INT 08(irq0) +; dw so irq0_7_handler,SEL_32bitCS,8E00h,0 + dw so timer_handler,SEL_32bitCS,8E00h,0 +; INT 09(irq1) + dw so irq1_handler,SEL_32bitCS,8E00h,0 +; INT 0Ah-0Fh (IRQ2-IRQ8) + dw 6 dup(so irq0_7_handler,SEL_32bitCS,8E00h,0) +; INT 10h-6Fh + dw 97 dup(so int_handler,SEL_32bitCS,8E00h,0) +; INT 70h-78h (IRQ8-IRQ15) + dw 8 dup(so irq8_15_handler,SEL_32bitCS,8E00h,0) +; INT 79h-FFh + dw 135 dup(so int_handler,SEL_32bitCS,8E00h,0) +idt_size = $-IDT +idtr dw idt_size-1 ; Предел IDT + dd ? ; Линейный адрес начала IDT +; Содержимое регистра IDTR в реальном режиме +idtr_real dw 3FFh,0,0 + +; Сообщения об ошибках при старте +v86_msg db "Процессор в режиме v86 - нельзя переключиться в PM$" +win_msg db "Программа на может бать запущена из под Windows$" + +; Таблица для перевода OE скан-кодов в ASCII +scan2ascii db 0,1Bh,'1','2','3','4','5','6','7','8','9','0','-','=',8 + db 0,'Q','W','E','R','T','Y','U','I','O','P','[',']',0 + DB 0,'A','S','D','F','G','H','J','K','L',';',27h,'`',0 ; LShift + db '\','Z','X','C','V','B','N','M',',','.','/',0 ; RShift + db '0','0',' ' ; SP +screen_addr dd 0 ; Текущая позиция на экране +N dd 64 ; Индекс в массиве MUS +NM dd 1 ; Счетчик длительности +; Массив пар звучания: 1-е число - частота, 2-е - длительность +MUS dw 1218,10, 767,10, 813,10, 912,10, 966,10, 912,30 + dw 1218,10, 609,10, 678,10, 767,10, 813,10, 767,30 + dw 912,10, 574,15, 609,5, 678,15, 767,5, 813,5 + dw 767,5, 678,20, 574,10, 609,10, 678,10, 767,10 + dw 678,10, 813,30, 1218,10, 767,10, 813,10, 912,10 + dw 966,10, 912,30, 1218,10, 609,10, 678,10, 767,10 + dw 813,10, 767,30, 912,10, 574,15, 609,5, 678,15 + dw 767,5, 813,5, 767,5, 678,20, 574,10, 609,10 + dw 678,10, 767,10, 678,10, 813,30, 0,2, 609,10 + dw 609,10, 912,10, 724,10, 609,10, 609,5, 678,5 + dw 724,5, 678,5, 574,15, 678,5, 678,10, 1024,10 + dw 813,10, 678,10, 678,5, 767,5, 813,5, 724,5 + dw 609,20, 678,5, 609,5, 574,5, 456,5, 342,5 + dw 384,5, 406,5, 456,5, 456,20, 483,20, 678,5 + dw 609,5, 574,5, 456,5, 342,5, 384,5, 406,5 + dw 456,5, 456,10, 483,10, 456,20, 0,2, 456,5 + dw 456,10, 483,10, 456,20, 0,30 +;MC = ($-MUS)/4; Music Count - количество нот +MC = 100 + +; Точка входа в 32-х битный защищенный режим +PM_entry: +; Установить 32-х битный стек и другие регистры + mov ax, SEL_flatDS + mov ds, ax + mov es, ax + mov ax, SEL_32bitSS + mov ebx, stack_l + mov ss, ax + mov esp, ebx +; Разрешить прерывания + sti +; и войти в вечный цикл + jmp short $ + +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +;! Обработчики прерываний ! +;! Многие не корректны - нельзя допускать ошибок ! +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +; Обработчик обычного прерывания +int_handler: + iretd +; Обработчик аппаратного прерывания IRQ0-IRQ7 +irq0_7_handler: + push eax + mov al, 20h + out 20h, al + pop eax + iretd +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +; Обработчик прерывания от таймера (int8) ! +;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +timer_handler: +; Сохранить регистры + push eax + push ebx + push es + push ds + + mov bx, SEL_32bitDS ; Загрузить сегмент данных + mov ds, bx + + dec NM ; Текущее время звучания + mov eax, NM ; Если не истекло, + cmp eax, 0 + jnz contin_mus ; то ничего не делать, иначе + ; Выключить звук + in al, 61h + and al, 0FCh + out 61h, al + delay 1 ; Пауза + ; Выбрать высоту следущеюй ноты + inc N ; Увеличить на ед. + mov eax, N ; Текущая позиция + mov ebx, 4 ; ! Размер пары в байтах + mul ebx ; Смещение пары, относительно начала массива + add eax, offset MUS ; Адрес + push eax ; сохранить +; xor eax, eax + mov ax, [eax] ; В AX - частота + ; Начать звучание + mov ebx, eax ; Подготовка + shr ebx, 8 ; параметров для + and ax, 00FFh ; записи в порты + push eax + mov ax, 0B6h ; \ + out 43h, ax ; _\outportb(0x43, 0xB6) + pop eax ; EAX = Частота & 0x00FF + out 42h, ax + xchg ax, bx ; ax = Частота >> 8 + out 42h, ax + in al, 61h + or al, 03h + out 61h, al + ; Выбрать длительность + pop ebx ; EBX = адрес текущей пары + xor eax, eax + mov ax, word ptr [ebx+2] ; EAX = Длительность + mov NM, eax + + cmp N, MC ; Если не в конце мелодии, + jb contin_mus ; то ничего, + mov N, 0 ; иначе - в начало массива + +contin_mus: +; mov NM, eax ; Сохранить текущее время звучания +; Снять с контроллера + mov al, 20h + out 20h, al +; Восстановить регистры, выйти + pop ds + pop es + pop ebx + pop eax + iretd +; Обработчик аппаратного прерывания IRQ8-IRQ15 +irq8_15_handler: + push eax + mov al, 20h + out 0A1h, al + pop eax + iretd +; Обработчик IRQ1 - прерывание от клавиатуры +irq1_handler: + push eax ; Это аппаратное прерывание - + push ebx ; сохранить регистры + push edx + push es + push ds + in al, 60h ; Прочитать скан-код нажатой клавиши +; cmp al, 0Eh ; Если он больше, чем обслуживаемый + cmp al, 39h ; Если он больше, чем обслуживаемый + ja skip_translate ; нами, - не обрабатывать + cmp al, 1 ; Если это ESC, + je esc_pressed ; выйти в реальный режим + mov bx, SEL_32bitDS ; Иначе: + mov ds, bx ; DS:EBX - таблица для перевода + mov ebx, offset scan2ascii ; скан-кода в ASCII + xlatb ; Преобразовать + mov bx, SEL_flatDS + mov es, bx ; ES:EBX - адрес текущей + mov ebx, screen_addr ; Позиции на экране + cmp al, 8 ; Если нажата BkSpace + je bs_pressed ; на соответствующий обработчик + cmp al, 0 ; + je skip_translate ; + mov es:[ebx+0B8000h], al ; иначе послать символ на экран + add dword ptr screen_addr, 2; Увеличить адрес позиции на 2 + ; Сменить позицию курсора + mov ebx, screen_addr + shr ebx, 1 +;! mov eax, ebx +;! mov ebx, 2 +;!!! div ebx +; mov ebx, eax +; mov ebx, screen_addr +; inc ebx + xor edx, edx + xor eax, eax + mov dx, 03D4h ; Регистры контроллера CRT + mov al, 0Fh ; обращение к регистру младшего байта + mov ah, bl + out dx, ax + mov al, 0Eh ; к рег. старшего байта + mov ah, bh + out dx, ax + jmp short skip_translate +bs_pressed: ; Нажат BkSpace: + mov al,' ' ; Вывести пробел + sub ebx, 2 ; в позиции предыдущего символа + mov es:[ebx+0B8000h], al + mov screen_addr, ebx ; и сохранить адрес передыд символа, + ; как текущий + ; Сменить позицию курсора + shr ebx, 1 +;! mov eax, ebx +;! mov ebx, 2 +;!!! div ebx +; mov ebx, eax +; mov ebx, screen_addr +; inc ebx + xor edx, edx + xor eax, eax + mov dx, 03D4h ; Регистры контроллера CRT + mov al, 0Fh ; обращение к регистру младшего байта + mov ah, bl + out dx, ax + mov al, 0Eh ; к рег. старшего байта + mov ah, bh + out dx, ax + +skip_translate: +; Разрешить работу клавиатуры + in al, 61h + or al, 80h + out 61h, al +; Послать EOI контроллеру прерываний + mov al, 20h + out 20h, al +; Восстановить регистры и выйти + pop ds + pop es + pop edx + pop ebx + pop eax + iretd + +; ******************* +; Нажата ESC +esc_pressed: +; Разрешить работу клавиатуры, послать EOI и восстановить регистры + in al, 61h + or al, 80h + out 61h, al + mov al, 20h + out 20h, al + cli +; Отключить звук + in al, 61h + and al, 0FCh + out 61h, al + pop ds + pop es + pop edx + pop ebx + pop eax +; Вернуться в реальный режим + + db 0EAh + dd offset RM_return + dw SEL_16bitCS +PM_seg ends + +; Сегмент стека, используется как 16-битный в 16-битной части программы и как +; 32-х битный (через селектор SEL_32bitSS) в 32-х битной части +Stack_seg segment para stack "STACK" +stack_start db 100h dup(?) +stack_l = $-stack_start ; Длина стека для инициализации ESP +Stack_seg ends + end start diff --git a/Protect/PM_INT8.9/ReadMe.txt b/Protect/PM_INT8.9/ReadMe.txt new file mode 100755 index 0000000..6431b1e --- /dev/null +++ b/Protect/PM_INT8.9/ReadMe.txt @@ -0,0 +1,30 @@ +Работа по ЦВМ +Макаренко Антона, 2084/3 + +Постановка: + Переход в защищннный режим, перехват прерываний от таймера(int8) и кла- +виатуры(int9). По нажатию клавиш алфавитно-цифровой клавиату - отобразить на +экране, параллельно вывести на PC Speaker мелодию. + +Компиляция: + Для компиляции проекта достаточно запустить файл mkpm.bat. +Ошибки, возникающие в процессе компиляции или линковки отражаются в файле +errmsg. + +Содержание папки: + +pm.asm - файл основного проекта +pm.exe - запускаемый файл проекта + +pm1.asm - файл первой версии проекта, перехват только клавиатуры и обработка + клавиш 1..+, BS. +pm2.asm - файл второй версии, перехват прерывания таймера, но не верный вывод + звука. +pm3.asm - рабочая версия проекта. + +для компиляции этих файлов достаточно запустить mk.bat c параметром pm1, pm2, +pm3, соответственно. + +nosound.exe - отключает звучание, в случае некорректной работы. + +остальные файлы - файлы компилятора и линковщика. diff --git a/Protect/PM_INT8.9/TASM.EXE b/Protect/PM_INT8.9/TASM.EXE new file mode 100755 index 0000000..f3867a6 Binary files /dev/null and b/Protect/PM_INT8.9/TASM.EXE differ diff --git a/Protect/PM_INT8.9/TLINK.EXE b/Protect/PM_INT8.9/TLINK.EXE new file mode 100755 index 0000000..b46896d Binary files /dev/null and b/Protect/PM_INT8.9/TLINK.EXE differ diff --git a/SCANCODE.COM b/SCANCODE.COM new file mode 100755 index 0000000..b691710 Binary files /dev/null and b/SCANCODE.COM differ diff --git a/asm/A.BAT b/asm/A.BAT new file mode 100755 index 0000000..8f35f5e --- /dev/null +++ b/asm/A.BAT @@ -0,0 +1,3 @@ +tasm.exe vga.asm +tlink.exe /t/x vga.obj +vga.com \ No newline at end of file diff --git a/asm/CMD.BAT b/asm/CMD.BAT new file mode 100755 index 0000000..1f3aa61 --- /dev/null +++ b/asm/CMD.BAT @@ -0,0 +1 @@ +%SystemRoot%\system32\cmd.exe \ No newline at end of file diff --git a/asm/DPMILOAD.EXE b/asm/DPMILOAD.EXE new file mode 100755 index 0000000..68f96b3 Binary files /dev/null and b/asm/DPMILOAD.EXE differ diff --git a/asm/DPMIMEM.DLL b/asm/DPMIMEM.DLL new file mode 100755 index 0000000..1d24230 Binary files /dev/null and b/asm/DPMIMEM.DLL differ diff --git a/asm/P_2.EXE b/asm/P_2.EXE new file mode 100755 index 0000000..108d62d Binary files /dev/null and b/asm/P_2.EXE differ diff --git a/asm/P_2.MAP b/asm/P_2.MAP new file mode 100755 index 0000000..2a00d2e --- /dev/null +++ b/asm/P_2.MAP @@ -0,0 +1,9 @@ + + Start Stop Length Name Class + + 00000H 000BFH 000C0H _TEXT CODE + 000C0H 000D8H 00019H _DATA DATA + 000E0H 001DFH 00100H STACK STACK + +Program entry point at 0000:0000 + diff --git a/asm/P_2.OBJ b/asm/P_2.OBJ new file mode 100755 index 0000000..7d12a37 Binary files /dev/null and b/asm/P_2.OBJ differ diff --git a/asm/T.bat b/asm/T.bat new file mode 100755 index 0000000..8e23a8a --- /dev/null +++ b/asm/T.bat @@ -0,0 +1 @@ +td.exe vga.com \ No newline at end of file diff --git a/asm/TASM.EXE b/asm/TASM.EXE new file mode 100755 index 0000000..f3867a6 Binary files /dev/null and b/asm/TASM.EXE differ diff --git a/asm/TD.EXE b/asm/TD.EXE new file mode 100755 index 0000000..fb51555 Binary files /dev/null and b/asm/TD.EXE differ diff --git a/asm/TLINK.EXE b/asm/TLINK.EXE new file mode 100755 index 0000000..b46896d Binary files /dev/null and b/asm/TLINK.EXE differ diff --git a/asm/file.txt b/asm/file.txt new file mode 100755 index 0000000..7c9adce --- /dev/null +++ b/asm/file.txt @@ -0,0 +1,2 @@ + Hello World sss dddd + dfs \ No newline at end of file diff --git a/asm/file2.txt b/asm/file2.txt new file mode 100755 index 0000000..8a97901 Binary files /dev/null and b/asm/file2.txt differ diff --git a/asm/p_2.asm b/asm/p_2.asm new file mode 100755 index 0000000..ee27d7a --- /dev/null +++ b/asm/p_2.asm @@ -0,0 +1,139 @@ +MASM +MODEL small +STACK 256 +.data +buffer dw 1 +Handle dw 0 +Handle2 dw 0 +filename db 'file.txt', 0 +filename2 db 'file2.txt', 0 +.code + +ASSUME ds:@data,es:@data +main: + mov ax,@data + mov ds,ax + mov es,0b:8000h +;------------------╬ЄъЁ√трхь Їрщы------------- + + mov di,30h + xor cx,cx ;рЄЁшсєЄ√ Їрщыр - юс√ўэ√щ Їрщы + mov bx,2 ;Ёхцшь фюёЄєяр юс√ўэ√щ - фюёЄєя фы  ўЄхэш -чряшёш + mov dx,1 ;хёыш Їрщы ёє∙хёЄтєхЄ, Єю юЄъЁ√Є№ хую. т юсЁрЄэющ ёыєўрх тхЁэєЄ№ ю°шсъє + mov dx,offset filename ;ЇюЁьшЁєхь єърчрЄхы№ эр шь  Їрщыр + mov ah,3dh ;эюьхЁ ЇєэъЎшш DOS + int 21h ;юЄъЁ√трхь Їрщы + mov [Handle], ax ;ёюїЁрэшь фхёъЁшяЄюЁ Їрщыр + mov bx,ax + jnc read ;хёыш Їрщы ёє∙хёЄтютры, Єю яхЁхїюф + jc ex ;яхЁхїюф т ёыєўрх ю°шсъш + +read: mov ah, 3Fh + mov cx,1 + mov dx, buffer + int 21h + + cmp ax, cx ; ╧ЁютхЁър EOF + jne eof ; ┼ёыш EOF, Єю т√їюфшь + + push ax + push bx + mov bx,dx + mov al,[bx] + mov [di],ax + pop bx + pop ax + + inc di + ; cmp [buffer], 13 ; ╧Ёюяєёърхь 13-√щ ёшьтюы + ; je read + ; cmp [buffer], 10 ; ╧ЁютхЁър ъюэЎр ёЄЁюъш + ; je exit + jmp read +eof: mov bx, Handle ; чръЁ√трхь Їрщы + mov ah, 3Eh + int 21h + + cld + sub di,30h + mov ax,di + mov cl,al + mov ah,al + mov al,' ' + mov di,30h + jmp first +ex: jmp exit +first: + mov al,'$' + cmp [di],al + mov al,' ' + je write;exit + cmp [di],al + je found + inc di + loop first + +faild: jmp write + +found: mov bx,di + inc di + cmp [di],al + je found2 + jmp first +found2: + lea si,[di+1] + mov ah, cl + rep movsb + dec ah + mov cl,ah + mov di,bx + jmp found + +write: ; xor cx,cx ;рЄЁшсєЄ√ Їрщыр - юс√ўэ√щ Їрщы + ; mov bx,1 ;Ёхцшь фюёЄєяр юс√ўэ√щ - фюёЄєя фы  ўЄхэш -чряшёш + ; mov dx,1 + ; mov dx,offset filename2 ;ЇюЁьшЁєхь єърчрЄхы№ эр шь  Їрщыр + + ; mov cx,5 + ; mov ah,5bh ;эюьхЁ ЇєэъЎшш DOS + ; int 21h ;ёючфр╕ь ш юЄъЁ√трхь Їрщы + + ; mov [Handle2], ax ;ёюїЁрэшь фхёъЁшяЄюЁ Їрщыр + ; mov bx,ax + + + + xor cx,cx ;рЄЁшсєЄ√ Їрщыр - юс√ўэ√щ Їрщы + mov bx,0002h ;Ёхцшь фюёЄєяр юс√ўэ√щ - фюёЄєя фы  ўЄхэш -чряшёш + mov dx,1 ;хёыш Їрщы ёє∙хёЄтєхЄ, Єю юЄъЁ√Є№ хую. т юсЁрЄэющ ёыєўрх тхЁэєЄ№ ю°шсъє + mov dx,offset filename2 ;ЇюЁьшЁєхь єърчрЄхы№ эр шь  Їрщыр + mov al,0001h + mov ah,3dh ;эюьхЁ ЇєэъЎшш DOS + int 21h ;юЄъЁ√трхь Їрщы + mov [Handle2], ax ;ёюїЁрэшь фхёъЁшяЄюЁ Їрщыр + mov bx,ax + + + + mov di,30h + ; mov bx, +xor ax,ax + mov ah, 40h + mov cx,30 + mov dx, di + int 21h + + mov ah,0dh + int 21h + + cmp ax, cx ; ╧ЁютхЁър EOF + + mov bx, Handle2 ; чръЁ√трхь Їрщы + mov ah, 3Eh + int 21h + jc exit ;яхЁхїюф т ёыєўрх ю°шсъш + +exit: + mov ax,4c00h + int 21h +end main