227 lines
12 KiB
C++
Executable File
227 lines
12 KiB
C++
Executable File
// Пример оформления программы
|
||
|
||
// Работа N 0
|
||
// Измерение времени выполнения фрагмента программы
|
||
// Студенты гр 000.0 Иванофф, Петрофф, & Сидорофф
|
||
//
|
||
|
||
#include <dos.h>
|
||
#include <bios.h>
|
||
#include <stdio.h>
|
||
#include <conio.h>
|
||
|
||
#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. Определите в какие команды Ассемблера оттранслирован с языка СИ
|
||
оператор цикла. Напишите на уровне Ассемблера свой вариант цикла.
|
||
Сравните, результаты представте преподавателю.
|
||
*/
|