Files
templates/Labv1.cpp
2024-09-10 22:24:24 +03:00

227 lines
12 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Пример оформления программы
// Работа 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. Определите в какие команды Ассемблера оттранслирован с языка СИ
оператор цикла. Напишите на уровне Ассемблера свой вариант цикла.
Сравните, результаты представте преподавателю.
*/