Разработать и отладить программу расчета выражения
Разработать и отладить программу расчета выражения
- Задание с выбором варианта коэффициентов
- Описание алгоритма задачи
- Описание отдельных процедур
- Листинг программы с комментариями
- Листинг результатов выполнения работы
- Список литературы
Для любого обращения к памяти в процессорах Intel используется логический адрес, состоящий из 16-битного селектора, определяющего сегмент, и 32- или 16-битного смещения — адреса внутри сегмента. Отдельный сегмент памяти — это независимое защищенное адресное пространство, для которого определены размер, разрешенные способы доступа (чтение/запись/исполнение кода) и уровень привилегий. Если доступ к памяти удовлетворяет всем условиям защиты, процессор преобразует логический адрес в 32- или 36-битный линейный. Линейный адрес — это адрес в несегментированном непрерывном адресном пространстве, который совпадает с физическим адресом в памяти, если отключен режим страничной адресации. Чтобы получить линейный адрес из логического, процессор добавляет к смещению линейный адрес начала сегмента, который хранится в поле базы в сегментном дескрипторе. Сегментный дескриптор — это восьмибайтная структура данных, расположенная в таблице GDT или LDT; адрес таблицы находится в регистре GDTR или LDTR, а номер дескриптора в таблице определяется из значения селектора.
Задание на курсовую работу
Разработать и отладить программу расчета выражения вида:
для значений Х от Xmin до Xmax с шагом 1 при а=2; В=1; С=4; Хмин=2; Хмах=6.
Оформить вывод фамилии и инициалов автора, уникального идентификационного номера, а также текущей даты.
Результаты вычислений вывести в виде таблицы значений X и Y на экране дисплея.
- Описание алгоритма задачи
- Организация сегмента данных.
Программа на Ассемблере состоит из логически самостоятельных частей, называемых сегментами. Для исполнения сегменты программы заносятся в отдельные участки оперативной памяти. Модуль программы может содержать от одного до трех типов сегментов – сегмент данных, стека и кода. Сегмент кода является обязательным, остальные могут отсутствовать (например, сегмент данных или стека) или быть объединены (сегмент кода и данных). Директиву ASSUME назначения сегментных регистров сегментам данных, стека, кода можно разместить перед сегментом кода или в первой его строке.
assume CS:Code, DS:Data, SS:Stackg
Начало и конец программного модуля обозначается с помощью связанных директив NAME и END.
Псевдокоманда — это директива ассемблера, которая приводит к включению данных или кода в программу, хотя сама она никакой команде процессора не соответствует. Псевдокоманды определения переменных указывают ассемблеру, что в соответствующем месте программы располагается переменная, определяют тип переменной (байт, слово, вещественное число и т.д.), задают ее начальное значение и ставят в соответствие переменной метку, которая будет использоваться для обращения к этим данным. Псевдокоманды определения данных записываются в общем виде следующим образом:
имя_переменной d* значение
где D* — одна из нижеприведенных псевдокоманд:
DB — определить байт;
DW — определить слово (2 байта);
DD — определить двойное слово (4 байта);
DF — определить 6 байт (адрес в формате 16-битный селектор: 32- битное смещение);
DQ — определить учетверенное слово (8 байт);
DT — определить 10 байт (80-битные типы данных, используемые FPU).
Поле значения может содержать одно или несколько чисел, строк символов (взятых в одиночные или двойные кавычки), операторов ? и DUP, разделенных запятыми. Все установленные таким образом данные окажутся в выходном файле, а имя переменной будет соответствовать адресу первого из указанных значений. Например, набор директив
Data SEGMENT
KR_RAB DB 'Контрольная работа № 1',13,10,' ------------------------',13,10,'$' Family DB ' Сердюк Владимир Леонидович',13,10,' -------------',10,13,'$' MESS DB ' Уникальный идентификационный номер 09',13,10,'------- ',13,10,'$'
ZAD DB ' Задание: Решить уравнение Y=A*(X*X)+B*X+C',13,10,'',13,10,'$' ZAD1 DB 'при А=2; В=1; С=4; Хмин=2; Хмах=6; Шаг=1.',13,10,' ',13,10,'$'
MES DB ,13,10,' $'
MESSS DB ,13,10, ' Сегодня: ','$'
MESSSS DB ,13,10, ' ','$'
Y DB 2D
X DB 2D
DAT DB 10 DUP(?)
DATT DB 10 DUP(?)
REZ_SHOW DB 10 DUP(?)
Data ends
заполняет данными 78 байта. Первые 22 байт содержат ASCII-коды символов строки «Контрольная работа № 1» и переменная KR_RAB DB указывает на первую букву в этой строке, так что команда
mov al,text_string
считает в регистр AL число 8Аh (код русской буквы К). Если вместо точного значения указан знак ?, переменная считается неинициализированной и ее значение на момент запуска программы может оказаться любым. Если нужно заполнить участок памяти повторяющимися данными, используется специальный оператор DUP, имеющий формат счетчик DUP (значение). Например, вот такое определение:
DAT DB 10 DUP(?)
table_512w dw 512 dup(?)
создает массив из 10 неинициализированных слов, на первое из которых указывает переменная DAT. В качестве аргумента в операторе DUP могут выступать несколько значений, разделенных запятыми, и даже дополнительные вложенные операторы DUP.
- Организация сегмента стека для временного сохранения и восстановления промежуточных результатов
Stackg segment Stack
DB 100H DUP(?) стек размером 256 байт.
Stackg ENDS
- Организация сегмента кода в виде основной программы, и набора вспомогательных подпрограмм-процедур.
Объявление сегмента кода.
Code segment
Обработка значений Х
MOV AX,DATA DATA в AX
MOV DS,AX AX в DX
XOR AX,AX обнуляем ax
MOV CX,6D заносим значение счетчика цикла в cx т.е до 6-и.
MOV SI,1 индекс начального элемента в cx т.е. 1.
MOV DAT[Si],028H Y в si
inc Si увеличиваем SI на 1
MOV DAT[Si],083H | в si
inc Si SI +1
GOO:
mov BH,X значение X в bh
mov DAT[Si],BH х в si
Переход к следующей ячейки памяти
inc Si
Увеличиваем число Х на еденицу.
inc X инкремент X т.е. х+1
Записываем значение в SI
MOV DAT[Si],0CFH значение | в si
inc Si инкремент si
MOV DAT[Si],083H значение | в si
inc Si инкремент si
loop GOO повторять цикл пока х не равен 6
Обработка значений Y
MOV AX,DATA DATA в AX
MOV DS,AX AX в CX
XOR AX,AX обнуляем AX
MOV CX,5D количество элементов Y
MOV SI,1 первый элемент =1
MOV REZ_SHOW[si],029H Y в SI
inc si
MOV REZ_SHOW[si],083H | в SI
inc si
Calculate:
Считаем
MOV AL,Y Хмин=1 в AL
умножение целочисленное без учета знака.
MUL AL X*X
MOV BL,2D A в BL
Умножение целочисленное без учета знака.
MUL BL A*X*X
Сложение т.к. В=1, умножение не выполняем.
ADD AL,Y A*X*X+B*X
Прибавляем С.
ADD AL,4D A*X*X+B*X+C
L1: Сравнение и счет после 10
Сравниваем результат с 10 если больше то на метку L2 иначе продолжаем программу дальше
CMP AL,10
JB L2
MOV BL,10 10 в BL
Деление на 10
DIV BL
Результат деления в SI.
MOV REZ_SHOW[si],AL
Переход к следующей ячейки памяти.
INC SI
AH в SI
MOV REZ_SHOW[si],AH
Переход к следующей ячейки памяти.
INC SI
Разделительная черта в SI
MOV REZ_SHOW[SI],083H
Переход к следующей ячейки памяти.
INC SI
Сравниваем с 10 если больше то на L3
CMP AL,10
JB L3
L2: Счет до 10
Результат до 10 в SI
MOV REZ_SHOW[si],AL
Переход к следующей ячейки памяти.
INC SI
Разделительная черта в SI.
MOV REZ_SHOW[SI],083H
Переход к следующей ячейки памяти.
INC SI
Повторение цикла
L3:
Х увеличиваем на 1
INC Y
Повторить цикл Calculate
LOOP Calculate
Обработка вида таблицы выполнена по подобию обработки значений Х.
- Описание отдельных процедур.
Вывод системной даты основан на использовании недокументированного прерывания 29H то есть быстрого вывода значения на экран.
Рассмотрим вывод системной даты.
CMOS 0Bh – управляющий регистр В
mov AL,0Bh
Порт 70h – индекс CMOS
out 70h,al
Порт 71h – данные CMOS.
in al,71h
Обнулить бит 2 (форма чисел - BCD).
and al,11111011b
Записать обратно.
out 71h,al
Затем выводим на экран день, месяц и год .
CMOS 07h – день.
mov al,7
Обращение к процедуре cmoss.
call cmoss
Вывод тире.
mov al,'-'
Прерывание быстрого вывода на экран.
int 29h
CMOS 08h – месяц.
mov al,8
Обращение к процедуре cmoss.
call cmoss
Вывод тире.
mov al,'-'
Прерывание быстрого вывода на экран.
int 29h
CMOS 32h – две старшие цифры года.
mov al,32h
Обращение к процедуре cmoss.
call cmoss
CMOS 09h – две младшие цифры года
mov al,9
Обращение к процедуре cmoss.
call cmoss
Выводим букву г.
mov al,'г'
Прерывание быстрого вывода на экран.
int 29h
Объявление процедуры CMOSS
cmoss proc near
Послать в AL в индексный порт CMOSS.
out 70h,al
Считать данные в AL
in al,71h
Отправить в стек.
push ax
Выделить старшие 4 – байта.
shr al,4
Добавляем ASCII цифру 0
add al,'0'
Выводим на экран
int 29h
Считываем из стека.
pop ax
Выделяем младшие 4 – байта.
and al,0Fh
Добавляем ASCII цифру 0
add al,30h;al
Вывод на экран
int 29h
ret 7
Конец процедуры.
cmoss endp
- Листинг программы с комментариями.
Data SEGMENT
KR_RAB DB ' Контрольная работа № 1',13,10,'-----------',13,10,'$'
Family DB ' Сердюк Владимир Леонидович',13,10,' ---',10,13,’$’
MESS DB ' Уникальный идентификационный номер',13,10,'---',13,10,'$'
ZAD DB 'Задание: Решить уравнение Y=A*(X*X)+B*X+C',13,10,' ',13,10,'$'
ZAD1 DB ' при А=2; В=1; С=4; Хмин=2; Хмах=6; Шаг=1.',13,10,' ',13,10,'$'
MES DB ,13,10,' $'
MESSS DB ,13,10, ' Сегодня: ','$'
MESSSS DB ,13,10, ' ','$'
Y DB 2D ;резервируем память под переменную Y
X DB 2D ; резервируем память под переменную Х
DAT DB 10 DUP(?) ; 10 DUP результат в символьном формате
DATT DB 10 DUP(?) ; 10 DUP результат в символьном формате
REZ_SHOW DB 10 DUP(?) ; результат в символьном формате
Data ends
;-------------------------------------------------------------------
Stackg segment Stack
DB 100H DUP(?) стек размером 256 байт.
Stackg ENDS
assume CS:Code, DS:Data, SS:Stackg
;------------------------------------------------------------------
Code segment
Start:
MOV AH, 00H функция задания режима экрана
MOV AL, 03H ЦВ текстовый, 25 строк по 80 знаков
INT 10H
;------------------------------------------------------------------------;
;------------------------------------------------------------------------;
ОБРАБОТКА И ВЫВОД ЗНАЧЕНИЯ X
MOV AX,DATA
MOV DS,AX AX в DX
XOR AX,AX обнуляем ax
MOV CX,6D значение счетчика цикла в cx
MOV SI,1 индекс начального элемента в cx
MOV DAT[Si],028H значение Y
inc Si инкремент SI
MOV DAT[Si],083H значение |
inc Si инкремент SI
GOO:
mov BH,X X в bh
mov DAT[Si],BH записываем в массив i
inc Si следующая ячейка памяти
inc X инкремент X
MOV DAT[Si],0CFH значение |
inc Si следующая ячейка памяти
MOV DAT[Si],083H значение |
inc Si следующая ячейка памяти
loop GOO повторить цикл
;------------------------------------------------------------------
mov ah,09h функция вывода на экран
lea dx,KR_RAB
INT 21H вывод строки
mov ah,09h функция вывода на экран
lea dx,Family
INT 21H вывод строки
mov ah,09h
lea dx,MESS
INT 21H
mov ah,09h
lea dx,ZAD загрузка ZAD в DX
INT 21H
mov ah,09h
lea dx,ZAD1 загрузка ZAD1 в DX
INT 21H
mov ah,09h
lea dx,MES загрузка MES в DX
INT 21H прерывание №21
;------------------------------------------------------------------
MOV CX,17 резервируем память
MOV SI,1 1 в SI
showW:
mov AH,02h функция вывода значения из al на экран
mov dl,DAT[Si] запись в массив i
add dl,30h преобразуем число в символ
int 21h
inc SI инкремент SI
loop showW повтор цикла
mov ah,09h вывод на экран MES
lea dx,MES
INT 21H
;--------------------------------------------------------------------;
;--------------------------------------------------------------------;
ОБРАБОТКА ТАБЛИЦЫ
MOV AX,DATA
MOV DS,AX
XOR AX,AX обнуляем ax
MOV CX,6D значение счетчика цикла в cx
MOV SI,1 начальное значение в si
MOV DATT[Si],094H значение Y
inc Si инкремент SI
MOV DATT[Si],083H значение |
inc Si инкремент SI
GOOO:
mov BH,094H X в bh
mov DATT[Si],BH запись в массив i
inc Si инкремент SI
MOV DATT[Si],094H значение --
inc Si инкремент si
MOV DATT[Si],083H значение |
inc Si инкремент si
loop GOOO повторить цикл
;--------------------------------------------
MOV CX,17
MOV SI,1
showWW:
mov AH,02h вывод на экран
mov dl,DATT[Si] запись в массив i
add dl,30h преобразуем число в символ
int 21h
inc SI инкремент si
loop showWW повторить цикл
mov ah,09h вывод на экран MES
lea dx,MES
INT 21H
;----------------------------------------------
;--------------------------------------------------------------------;
;--------------------------------------------------------------------;
ОБРАБОТКА И ВЫВОД ЗНАЧЕНИЯ Y
MOV AX,DATA
MOV DS,AX
XOR AX,AX обнуляем ax
MOV CX,5D максимум в цикле cx
MOV SI,1 начальный элемент цикла в cx
MOV REZ_SHOW[si],029H значение Y
inc si
MOV REZ_SHOW[si],083H значение |
inc si
Calculate: Считаем
MOV AL,Y Хмин=1 в AL
MUL AL X*X
MOV BL,2D A в BL
MUL BL A*X*X
ADD AL,Y A*X*X+B*X прибавили В*Х
ADD AL,4D A*X*X+B*X+C плюс С
L1: сравнение и счет после 10
CMP AL,10 сравниваем результат с 10
JB L2 если больше, то на L2 иначе дальше
MOV BL,10 10 в BL
DIV BL делим на 10
MOV REZ_SHOW[si],AL результат деления в si
INC SI следующая ячейка
MOV REZ_SHOW[si],AH AH в старший разряд AX
INC SI следующая ячейка
MOV REZ_SHOW[SI],083H вертикальная черта
INC SI следующая ячейка
CMP AL,10 если больше то на L3
JB L3
L2:
MOV REZ_SHOW[si],AL AL в SI
INC SI следующая ячейка
MOV REZ_SHOW[SI],083H | в следующую ячейку
INC SI новая ячейка памяти
L3:
INC Y Х увеличиваем на 1
LOOP Calculate повторить цикл Calculate
;------------------------------------------------------------------
Вывод на экран полученного массива
MOV SI,1 в SI 1
mov cx,17D размер буфера CX
show:
mov ah,02h вывод на экран
mov dl,REZ_SHOW[si] SI в DL
add dl,30h символ в число
int 21h прерывание 21h
inc si следующая ячейка
loop show повторить цикл
;----------------------------------------------------------------------;
;----------------------------------------------------------------------;
mov ah,09h
lea dx,MES вывод MES на экран
INT 21H
mov ah,09h
lea dx,MESSS вывод MESSS на экран
INT 21H
mov ah,09h
lea dx,MESSSS вывод MESSSS на экран
INT 21H
;------------ВЫВОД СИСТЕМНОЙ ДАТЫ------------------------------
;--------------------------------------------------------------------------
mov AL,0Bh CMOS 0Bh –управляющий регистр B
out 70h,al порт 70h - индекс CMOS
in al,71h порт 71h – данные CMOS
and al,11111011b обнулить бит 2 (форма чисел- BCD)
out 71h,al и записать обратно
;--------------------------------------------------------------------------
mov al,7 CMOS 07h - день
call cmoss вызов процедуры
mov al,'-' тире
int 29h быстрый вывод
;----------------------------------------------------------------------
mov al,8 CMOS 08h – текущий месяц
call cmoss вызов процедуры
mov al,'-' тире
int 29h быстрый вывод
;-----------------------------------------------------------------------
mov al,32h CMOS 32h – две старшие цифры года
call cmoss вызов процедуры
mov al,9 CMOS 09h – две младшие цифры года
call cmoss вызов процедуры
mov al,'Ј' символ г
int 29h прерывание 29h
JMP EXIT безусловный переход на ВЫХОД
cmoss proc near процедура
out 70h,al послать AL в индексный порт CMOS
in al,71h прочитать данные
push ax в стек
shr al,4 выделить старшие 4 бита
add al,'0' добавить 0
int 29h быстрый вывод
pop ax из стека
and al,0Fh выделить младшие 4 бита
add al,30h добавить ASCII-код цифры 0
int 29h быстрый вывод символа на экран
ret 7
cmoss endp
;-------------------------------------------------------------
exit:
mov ax,00h
int 16h ждем нажатие любой клавиши
;-------------------------------------------------------------
MOV AX,4C00H символьная функция возврата
INT 21H в диспетчер MS DOS.
Code ENDS
END Start адрес начала программы
- Листинг результатов выполнения работы
- Абель П. Язык Ассемблера для IBM PC и программирования. – М.: Высшая школа, 1992 г.
- Нортон П, Уилтон. IBM PC и PS/2.– Руководство по программированию. М.: Радио и связь, 1994 г.
- Пильщиков В.Н. Программирование на языке АСС IBM PC .–М.: Диалог- МИФИ, 1996 г.
- Скэнлон Л. Персональные ЭВМ PC и XT. Программирование на языке Ассемблера.– М.: Радио и связь, 1989 г.
- Юров В.И. Assembler.– С-Пб: Питер, 2006.