регистрация / вход

Микропроцессор i8086/i8088

Два основных направления развития производства микросхем. Разработка архитектуры и полупроводниковые технологии. Структура микропроцессора i8086, операционное устройство. Назначение максимальных и минимальных режимов. Разработка программного обеспечения.

МОСКОВСКИЙ ГОСУДАРСТВЕННЫЙ ОТКРЫТЫЙ УНИВЕРСИТЕТ

Кафедра информационных систем и измерительных технологий

КУРСОВОЙ ПРОЕКТ

по предмету: Системное программирование

Выполнил: студентка 4 курса

специальность 200106

Шифр 604992/с

Проверил:

Москва 2008


содержание

Введение. 3

1. Структура микропроцессора i8086. 8

2. Разработка программного обеспечения. 17

2.1. Основной алгоритм.. 17

2.2. Отладка и тестирование. 19

2.3. Подсчёт контрольного кода четности. 23

2.4. Битовое маскирование. 24

2.5. Подсчет в массиве байтов с четным количеством бит. 26

2.6. Проверка элементов массива на чётность. 27

3. Ввод числовых данных. 29

4. Алгоритм проверки ввода десятичного числа. 31

Приложение. 32

Литература. 57

Введение

Производство интегральных микросхем на сегодняшний день - фундамент не только индустрии информационных и компьютерных технологий, но и многих смежных отраслей - бытовой электроники, медицины, военной промышленности.

Следует различать два основных направления развития производства микросхем. Первое - разработка архитектуры, включающая в себя выбор тех или иных функций и особенностей будущих схем, микросхемотехнику и компоновку на кристалле функциональных блоков и их элементов. А также - оптимизация готовых блоков с целью упрощения и удешевления их массового производства.

Второе направление – это полупроводниковые технологии производства микросхем. Сюда входят научная разработка и воплощение в «кремний» всё более быстрых и маленьких транзисторов, цепей связи между ними, создание новых материалов и оборудования для этого, а также «manufacturability» - область знаний о том, как производить микросхемы более высокого качества, более быстрые, с меньшим числом дефектов.

На сегодняшний день проще назвать те области, которые пока не зависят от достижений микроэлектроники. Современный человек просто обязан иметь представление о том, что такое микроэлектроника и технология производства микросхем. Вершиной же этой технологии являются микропроцессоры - самые сложные и важные интегральные схемы. [10]

Интегральные микросхемы делают на поверхности монокристаллического кремния путём последовательного создания различных слоёв на тонкой (меньше миллиметра) круглой (диаметром до 30 см) кремниевой пластине, именуемой подложкой. Слои формируются при помощи различных процессов с использованием химических реактивов, газов и света. Более двадцати слоев «витиевато» соединены между собой, дабы сформировать схему микропроцессора с трехмерной структурой. Точное число слоев на подложке (вафле) зависит от дизайн - проекта конкретного процессора.

Процессы формирования различных слоев и рисунков элементов микросхемы на подложке достаточно хитроумны, однако в их основе лежит одна простая идея: поскольку размеры создаваемого рисунка настолько малы, что осаждать материалы в нужных местах просто невозможно, поступают проще - материал осаждают сразу на всю поверхность подложки, а затем его аккуратно удаляют из тех мест, где он не нужен. Для этого служит процесс фотолитографии.

Прежде всего, на подложке создается тонкий (обычно тоньше одного


микрона) и сплошной, без дефектов, слой нужного материала.

Рис.1. «Чистая комната»

Далее на нём проводится фотолитография. Для этого сначала на поверхность пластины наносится тонкий слой светочувствительного материала (фоторезист). Затем пластина с фоторезистом помещается в прецизионную установку, где нужные участки поверхности облучаются ультрафиолетом сквозь прозрачные отверстия в фотомаске (фотошаблоне). Маска содержит соответствующий (наносимый на поверхность) рисунок, который разрабатывается для каждого слоя.

Под действием ультрафиолета облученные участки фоторезиста меняют свои свойства так, что становится возможным их селективно удалить. После снятия фоторезиста остаются открытыми области поверхности пластины, над которыми требуется совершить нужную операцию (убрать слой диэлектрика или металла).

При производстве приходится совершать операции фотолитографии до 20-25 раз - каждый раз над новым слоем.

Кристаллы микросхем должны производиться в условиях контролируемого и чистого воздуха. Поскольку функциональные элементы на микрочипах малы, любая чужеродная частица (пыль, дым, чешуйки кожи), попавшая на пластину на промежуточных стадиях её производства, способна вывести из строя целый кристалл. Чтобы этого не допустить, для производства используются «чистые комнаты», которые классифицируются по размеру и количеству микрочастиц в единице объёма воздуха.

Например, комнаты класса 1, используемые в современном производстве, примерно в тысячу раз чище, чем хирургическая операционная. «Чистая комната» управляет чистотой воздуха путём фильтрации поступающего воздуха, удалением грязи с установок, ламинарным перемещением воздуха от потолка к полу (примерно за шесть секунд), регулировкой влажности и температуры. Люди в «чистых комнатах» ходят в специальных скафандрах, закрывающих, в том числе, весь волосяной покров. Для устранения вибраций чистые комнаты располагаются на собственном виброзащитном фундаменте.

Иногда применяется взрывная фотолитография. Сначала формируется рисунок (вытравливаются окна в фоторезисте или временном слое диэлектрика), затем на поверхность пластины наносится сплошной слой нового материала (металла), и пластина помещается в реактив, удаляющий остатки фоторезиста или временный диэлектрик. В результате удаляемый слой как бы «взрывается» изнутри, унося с собой лежащие на нем куски нанесенного последним металла, а в предварительно «открытых» участках металл остался и сформировал нужный нам функциональный рисунок. [10]

Межсоединения - электрические соединения между транзисторами в микросхемах создаются при помощи нескольких металлических слоев, подобно тому, как на сложных печатных платах (материнских платах, видеокартах, модулях памяти) отдельные микросхемы, транзисторы, резисторы и конденсаторы объединяются в законченные схемы. Только здесь это происходит на микромасштабах. В качестве металла для межсоединений в современных микропроцессорах, изготавливаемых по 130-нм и 90-нм технологиям выступает медь. Новейшие микропроцессоры насчитывают от семи до десяти слоев межсоединений, причём у разных производителей число слоев может разниться: для 0,13-микронного и 90-нм техпроцессов Intel Pentium 4 имеет семь или восемь слоев соответственно, а AMD Athlon 64 - девять слоев.


Для уменьшения паразитных связей между слоями металлизации используется уже не традиционный диоксид кремния, а специальный материал (low-k) с более низкой диэлектрической проницаемостью.

Таким образом, на поверхности кремниевой пластины создается сложная трехмерная структура толщиной в несколько микрон, которая, собственно, и является электронной схемой. Сверху схема покрывается толстым (микроны) слоем пассивирующего диэлектрика, защищающего от внешних воздействий. В нём лишь открываются окна для больших, стороной в десятки микрон, квадратных металлических контактных площадок, через которые на схему подаются извне питающие напряжения и электрические сигналы. Снизу основой микросхемы служит кремниевая пластина толщиной в сотни микрон.

После завершения технологических процедур каждый из кристаллов тестируется, а потом пластина разрезается на отдельные кристаллы. Далее каждый чип упаковывается в свой корпус, что позволяет подключать его к другим приборам. Все упакованные чипы тестируются еще раз и отгружаются заказчику.

1. Структура микропроцессора i8086

Микропроцессор i8086/i8088 принадлежит к 16-разрядным процессорам первого поколения. Большая интегральная схема i8086 с геометрическими размерами 5,5x5,5 мм имеет 40 контактов, содержит около 29 000 транзисторов и потребляет 1,7 Вт от источника питания +5 В, тактовая частота составляет 5; 8 или 10 МГц.

Микропроцессор выполняет операции над 8 - и 16-разрядными данными, представленными в двоичном или двоично-десятичном виде, может обрабатывать отдельные биты, а также строки или массивы данных. Он имеет встроенные аппаратные средства умножения и деления.

Микропроцессор имеет внутреннее сверхоперативное запоминающее устройство (СОЗУ) емкостью 14x16 байт. Шина адреса является 20-разрядной, что позволяет непосредственно адресовать 220 = 1 048 576 ячеек памяти (1 Мбайт).

Пространство адресов ввода/вывода составляет 64 Кбайт. В БИС i8086 реализована многоуровневая векторная система прерываний с количеством векторов до 256. Предусмотрена также организация прямого доступа к памяти, по которому микропроцессор прекращает работу и переводит шины адреса, данных и управления в высокоимпедансное состояние.

Среднее время выполнения команды занимает 12 тактов. Особенностью i8086 является возможность частичной реконфигурации аппаратной части для обеспечения работы в двух режимах - минимальном и максимальном. Режимы работы задаются аппаратно. В минимальном режиме, используемом для построения однопроцессорных систем, микропроцессор самостоятельно формирует все сигналы управления внутренним системным интерфейсом. В максимальном режиме, используемом для построения мультипроцессорных систем процессор формирует на линиях состояния двоичный код, который зависит от типа цикла шины. В соответствии с этим кодом системный контроллер К1810ВГ88 формирует сигналы управления шиной. Контакты, которые освободились в результате кодирования информации, используются для управления мультипроцессорным режимом. При использовании арифметического сопроцессора необходимо выбирать максимальный режим.


Структурная схема микропроцессора i8086. В МП i8086 применена конвейерная архитектура, которая позволяет совмещать во времени циклы исполнения и выборки из памяти кодов последующих команд. Это достигается параллельной работой двух сравнительно независимых устройств - операционного устройства и шинного интерфейса. Структурная схема МП i8086 показана на рис.1.1.

Рис.1.1. Структурная схема микропроцессора i8086.


Операционное устройство выполняет команду, а шинный интерфейс осуществляет взаимодействие с внешней шиной - выставляет адреса, считывает коды команд и операнды, записывает результаты вычислений в память или устройства ввода/вывода. [1,58]

Операционное устройство состоит из РОН, предназначенных для хранения промежуточных результатов вычислений - данных и адресов; АЛУ с буферными регистрами; регистра флагов; схемы управления и синхронизации, которая дешифрует коды команд и генерирует управляющие сигналы для всех блоков схемы МП. Шинный интерфейс состоит из шестибайтной регистровой памяти, которая называется очередью команд, четырех сегментных регистров: CS, DS, ES, SS, указателя команд IP, сумматора, а также вспомогательных регистров связи и буферных схем шин адреса/данных.

Очередь команд работает по принципу FIFO (FirstInput - FirstOutput, т.е. «первый пришел - первый вышел») и сохраняет на выходе порядок поступления команд. Длина очереди - 6 байт. Если операционное устройство занято выполнением команды, шинный интерфейс самостоятельно инициирует опережающую выборку кодов команд из памяти в очередь команд.

Выборка из памяти очередного командного слова осуществляется тогда, когда в очереди обнаруживаются два свободных байта. Очередь увеличивает быстродействие процессора в случае последовательного выполнения команд. При выборке команд переходов, запросов и возвращений из подпрограмм, обработки запросов прерываний очередь команд сбрасывается, и выборка начинается с нового места программной памяти.

Ещё одной задачей шинного интерфейса является формирование физического 20-разрядного адреса из двух 16-разрядных слов. Первым словом является содержимое одного из сегментных регистров CS, SS, DS, ES, а второе слово зависит от типа адресации операнда или кода команды. Суммирование 16-разрядных слов происходит со смещением на 4 разряда и осуществляется с помощью сумматора, который входит в состав шинного интерфейса.


Условное графическое изображение микропроцессора приведено на рис.1.2. Назначение контактов БИС зависит от режима работы процессора. Восемь контактов имеют двойное обозначение, причём обозначения в скобках соответствуют максимальному режиму. В таблице 1.1. приведены назначения контактов, одинаковые для обоих режимов, в таблице 1.2. - назначение контактов, которые используются только в минимальном режиме, в таблице 1.3. - назначение контактов, которые используются только в максимальном режиме. Буквой z обозначены трехстабильные выходы, которые переводятся в высокоимпедансное состояние при переходе микропроцессора в режим захвата; в скобках приведены альтернативные обозначения контактов, которые встречаются в литературе.

Рис.1.2. Графическое изображение БИС МП i8086.


Таблица 1.1. Назначение контактов МП i8086 для

минимального и максимального режимов

Обозначение Назначение Тип
AD15 - АО Address/data - мультиплексная двунаправленная шина адреса/данных (ADB - AddressDataBus), по которой с разделением во времени передаются адреса и данные. Адреса передаются в первом такте цикла шины и сопровождаются сигналом ALE, а данные - во второй половине цикла шины и сопровождаются сигналом DEN

Вход/ выход

(z)

BHE/ST7 ByteHighEnable/Status 7 - выходной сигнал разрешения старшего байта/сигнал состояния. В первом такте цикла одновременно с адресной информацией передается сигнал ВНЕ. Активный (L) уровень ВНЕ означает, что по старшей половине AD15 - AD8 шины адреса/данных передаются 8-разрядные данные. Сигнал ВНЕ используется для разрешения доступа к старшему банку памяти или к внешнему устройству с байтовой организацией, подключенному к старшей половине шины данных. В других тактах формируется сигнал состояния ST7 Выход (z)
RD Read - выходной сигнал чтения. Указывает на то, что МП выполняет цикл чтения

Выход

(z)

READY Ready - входной сигнал готовности, подтверждающий, что ячейка памяти или устройство ввода/вывода, адресуемое в команде, готово к взаимодействию с МП при передаче данных Вход
INTR InterruptRequest - входной сигнал запроса (при Н-уровне) маскированного прерывания. Если прерывания разрешены, МП переходит к подпрограмме обработки прерывания, в противном случае игнорирует этот сигнал Вход
RESET (CLR) Сигнал аппаратного сброса (при Н-уровце). Переводит МП в начальное состояние, при котором сброшены сегментные регистры (кроме CS, все разряды которого устанавливаются в единичное состояние), указатель команд IP, все флаги, регистры очереди команд и все внутренние триггеры устройства управления. Сигнал RESET не влияет на состояние РОН. Во время действия сигнала RESET все выходы, имеющие три состояния, переводятся в высокоимпедансное состояние; выходы, которые имеют два состояния, становятся пассивными. Минимальная продолжительность сигнала RESET при первом включении МП составляет 50 мкс, а при повторном запуске - четыре Вход
Обозначение Назначение Тип
TEST Test - входной сигнал проверки. Сигнал используется вместе с командой ожидания WAIT, выполняя которую, МП проверяет уровень сигнала TEST. Если TEST = 0, МП переходит к выполнению следующей после WAIT команды. Если TEST = 1, МП находится в состоянии ожидания, выполняет холостые такты и периодически, с интервалом 5TCLK, проверяет значение сигнала TEST Вход
CLK, (CLC) Clock - входные тактовые импульсы, обеспечивающие синхронизацию работы МП Вход
MN/MX Minimum/maximum - вход сигнала выбора минимального или максимального режимов. Определяет режим работы МП: при 1 - минимальный, при 0 - максимальный Вход
INTA InterruptAcknowledge - выходной сигнал подтверждения прерывания, определяющий чтение вектора прерывания Выход
ALE AddressLatchEnable - выходной сигнал разрешения фиксации адреса; выдается в начале каждого цикла шины и используется для записи адреса в регистр-фиксатор Выход
DEN (DE) DataEnable - выходной сигнал разрешения данных, который определяет появление данных на шине адреса/данных Выход (z)
DT/R (OP /IP) DataTransmit/Receive (Output-Input) - выходной сигнал передачи/приема данных; определяет направление передачи данных по ADB. Предназначен для управления шинными формирователями и действует на протяжении всего цикла шины Выход (z)
M/IO

Memory/Input-Output - выходной сигнал признака обращения к памяти (М/Ю = 1) или внешнему устройству

(М/Ю = 0). Используется для распределения адресного пространства памяти и устройств ввода/вывода

Выход (z)
WR Write - выходной сигнал записи. Указывает на то, что МП выполняет цикл записи в память или внешнее устройство, и сопровождает данные, которые выдаются МП на шину данных

Выход (z)

HOLD Hold - входной сигнал запроса захвата шин от внешнего устройства или контроллера прямого доступа к памяти Вход
HLDA HoldAcknowledge - выходной сигнал подтверждения захвата. Сигнал указывает на то, что МП перевел свои шины адреса/данных, адреса/состояния и управления в z-состояние Выход

Таблица 1.2. Назначение контактов МП i8086 в максимальном режиме

ST2 - ST0

(S2 - SO)

Выходные сигналы линий состояния. Характеризуют тип выполняемого цикла шины; используются для формирования управляющих сигналов

Выход

(z)

RQ/GTORQ/GT1 (RQ/ЁО) (RQ/БЦ Request/Grant (Request/Enable) - два входных/выходных сигнала запроса/предоставления локальной шины; используются для связи с другими процессорами, в частности, с арифметическим сопроцессором. Линия RQ/GT1 имеет меньший приоритет Вход/ выход
LOCK Lock - выходный сигнал блокировки (занятости) шины - сигнал монополизации управления шиной; формируется во время выполнения команды с префиксом LOCK и информирует другие процессоры и устройства о том, что они не должны запрашивать системную шину Выход
QS1. QSO Queue Status - два выходных сигнала состояния очереди; идентифицируют состояние внутренней шестибайтной очереди команд и действуют на протяжении такта синхронизации после выполнения операции над очередью. Сигналы QS1, QS0 предназначены для сопроцессора, который контролирует шину адреса/данных, фиксирует момент выборки из памяти программ предназначенной для него команды с префиксом ESC, а после этого следит за очередью команд и определяет момент, когда эта команда должна выполняться Выход

2. Разработка программного обеспечения

2.1. Основной алгоритм

Термин «чётность» в программировании может иметь двоякий смысл:

- первое; целое число считается чётным, если делится на два без остатка;

- второе; значение термина «чётность» используется применительно к флагу чётности (PF – ParityFlag), который предусмотрен в составе регистра флагов процессора i8086. Этот флаг устанавливается в 1, если младший байт результата предыдущей команды содержит чётное число битов, равных 1, и в 0 - нечётное.

Выберем предпочтительный вариант интерпретации термина «контроль четности». Для этого рассмотрим два алгоритма контроля и определим, какой из них окажется более чувствительным к изменению исходных данных.

Сначала определим общий принцип формирования контрольного кода. Очевидно, что использовать общее количество элементов массива нецелесообразно, так как тогда можно будет в лучшем случае обнаружить изменение размера массива, но не изменение отдельных его элементов. Более того, в большинстве языков программирования понятие «массив» предполагает набор данных, количество элементов в котором в процессе выполнения программы не изменяется (является константным). Соответственно, изменение размера как вариант изменения массива рассматривать нецелесообразно.

Обработку же отдельных элементов массива независимо от интерпретации термина «чётность» можно выполнять двумя способами:

Если размер массива не превышает ёмкости контрольного кода (количеству бит в двоичном представлении числа), то каждому элементу массива можно поставить в соответствие один бит в контрольном коде. При этом если элемент массива чётный, то соответствующий бит контрольного кода будем устанавливать в 1, в противном случае – в 0. В таком случае если произойдет изменение любого элемента массива таким образом, что изменится чётность этого элемента, контрольный код позволит не только обнаружить сам факт изменения информации, но и однозначно определить изменённый элемент.

Если размер массива превышает ёмкость контрольного кода, то однозначное соответствие между элементами массива и битами контрольного кода обеспечить невозможно. В таком случае можно подсчитывать количество чётных или, наоборот, нечётных элементов массива. Если изменится чётность какого-либо элемента массива, изменится и контрольная сумма, что позволит обнаружить сам факт изменения исходных данных.

Однако такой способ не гарантирует защиты от «компенсирующих» ошибок, то есть когда одновременно изменяется два (в общем случае – чётное количество) элементов, причём один становится вместо чётного нечётным, а второй – наоборот, вместо нечётного чётным. В такой ситуации контрольная сумма останется неизменной и изменение данных обнаружено не будет.

Для более надежного контроля сохранности данных используют, как правило, более сложные алгоритмы, например, CRC32 – подсчёт циклической контрольной суммы. Можно сделать вывод - в любом случае необходимо определить наиболее «устойчивую» интерпретацию термина «чётность» на уровне отдельного элемента массива.

Двоичное число является чётным в математическом смысле, если его самый младший бит равен нулю. Соответственно, изменение любых старших битов элемента массива никак не скажется на его чётности (нечётности).

При использовании механизма подсчёта битов, аналогичном установке флага чётности, изменение любого бита исходного байта изменит и контрольное число. Естественно, что это также не обеспечивает защиты от «компенсирующих» ошибок, когда будет изменена сразу пара (или чётное количество) битов. Тем не менее, очевидно, что вариант подсчёта битов в исходных элементах массива более чувствителен к изменению исходных данных, чем проверка делимости элементов на два без остатка.

На основании вышеизложенного примем решение использовать алгоритм подсчёта битов в элементе массива. Расчёт же контрольного кода сделаем адаптивным, то есть для массивов, размер которых не превышает разрядность контрольного кода, используем битовое маскирование, а для массивов большего размера – подсчёт количества «чётных» элементов.

Учитывая потенциальную возможность повторного использования, алгоритм вычисления контрольного кода чётности реализуем в виде подпрограммы.

2.2. Отладка и тестирование

Для отладки и тестирования основной подпрограммы разработаем программу, в которой будет реализована следующая функциональность:

- формирование контрольного массив данных и его заполнение с помощью генератора псевдослучайных чисел;

- вычисление контрольного кода чётности и его сохранение с помощью основной подпрограммы;

- вывод на экран значений элементов массива и контрольного кода чётности;

- интерактивное изменение какого-либо элемента исходного массива;

- пересчёт контрольного кода массива и сравнение с сохраненным ранее.

Тестовая программа будет разработана, как и основная подпрограмма, с использованием языка программирования Ассемблер.

В общем случае тестовая программа не обязательно должна разрабатываться на том же языке программирования, что и основной алгоритм, – можно было бы использовать любой язык программирования, позволяющий взаимодействовать с Ассемблером. Причём, разные языки программирования обеспечивают необходимое взаимодействие с помощью различных механизмов и определяют собственные ограничения. Так, C и C++ поддерживают подключение двоичных модулей, которые могут быть получены как результат компиляции ассемблерной программы. TurboPascal, например, поддерживает ассемблерные вставки на уровне исходных текстов.

Для разработки тестовой программы потребуется ряд вспомогательных подпрограмм, обеспечивающих, в частности, вывод на экран текстовых сообщений и числовых значений, ввод числовых данных, генерация случайных чисел. Рассмотрим основные из них:

1. Вывод на экран текстовых сообщений. Этот алгоритм будет использоваться для вывода пояснительных сообщений, приглашений к вводу данных и прочих.

2. Вывод на экран числовых значений - будет использоваться для отображения значений элементов массива и контрольного кода чётности. Если преобразовать число к строковому виду, то для непосредственного отображения можно будет использовать алгоритм вывода на экран текстового сообщения. Таким образом, реализация алгоритма может быть упрощена за счёт его разбиения на две составляющие:

- преобразовать число к строковому виду;

- вывести строку на экран.

3. Преобразование числа к строковому виду.

Наиболее распространенные варианты представления чисел – десятичное, восьмеричное, шестнадцатеричное и двоичное.

Символы ‘0’…’9’ располагаются в таблице ASCII-кодов последовательно, поэтому просто реализуется преобразование чисел в десятичное представление. Также десятичная форма отображения чисел является достаточно компактной. С учётом этого примем решение выводить числа на экран в десятичном виде.

4. Ввод числовых данных. С целью унификации визуального представления ввод числовых данных также будет осуществляться в десятичном представлении. Целесообразно усилить реализацию алгоритма проверкой введенного значения на превышение задаваемого в виде параметра лимита – это позволит использовать единообразно использовать разработанную подпрограмму и для ввода номера элемента массива, ограничив возможное значение размером массива, и для ввода нового значения элемента массива.

5. Генерация случайных чисел

В силу детерминированной природы компьютерных программ получить случайную последовательность чисел за счёт генерации невозможно. В программировании используется более точный термин – «псевдослучайная» последовательность. Это означает, что генерируемая последовательность чисел похожа на случайную, однако при повторении внешних условий, определяющих работу генератора, выходная последовательность повторится.

В качестве внешнего параметра генераторов псевдослучайных чисел, как правило, используют значение текущего времени компьютера в миллисекундах или количество тиков, прошедших с момента запуска компьютера. Такие внешние параметры хотя теоретически и могут быть повторены, вероятность их непроизвольного повторения практически равна нулю. Так как генерация случайных чисел будет использоваться только для автоматического заполнения тестового массива, особых требований к его «случайности» можно не предъявлять, что позволит использовать один из простейших генераторов.

Самый часто применяемый тип алгоритмов генерации псевдослучайных последовательностей – линейные конгруэнтные генераторы, описываемые общим рекуррентным соотношением:

Ij+1 = (aIj + c) MODm

При правильно выбранных числах a и c эта последовательность возвращает

все числа от нуля до m–1 псевдослучайным образом и её периодичность сказывается только на последовательностях порядка m. Если число a подобрано очень тщательно, может оказаться, что число c равно нулю. Так, классический стандартный генератор Льюиса, Гудмана и Миллера использует a=16807 (75) при m=231-1, а генераторы Парка и Миллера используют a=48271 и a=69621 (при том же m).

Реализуем последний из описанных вариантов, используя в качестве начального значения I текущее значение тактов таймера, которое хранится в виде двойного слова в области данных BIOS по адресу 0040: 006C.

6. Компоновка алгоритмов. Алгоритмы, реализуемые в программе, в интересах лучшей читаемости исходных текстов и возможности повторного использования оформлены в виде подпрограмм. Передача параметров в подпрограммы и получение результатов будет осуществляться через регистры процессора. Модификация регистров внутри подпрограмм в целях минимизации неуправляемых побочных эффектов будет сведена к минимуму. Глобальные переменные будут использоваться по возможности только во вспомогательных алгоритмах.

С учётом сформулированных ранее проектных решений, касающихся формирования контрольного числа, очевидно, что чем больше разрядность контрольного кода, тем большей ёмкости массивы могут быть обработаны более точным и информативным методом – методом битового маскирования.

С учётом же того, что в настоящее время наиболее распространены персональные компьютеры с 32-разрядной архитектурой, целесообразно ограничить ёмкость контрольного числа 32-мя битами.

Вопрос типа элементов в обрабатываемых массивах не является существенным, так как в контексте языка программирования Ассемблер речь может идти только о байтовых массивах, о массивах машинных слов (16 разрядов) и двойных слов (32 разряда). Если принять во внимание, что в любом случае под массив отводится непрерывная область памяти, то массив машинных слов можно рассматривать как байтовый массив двойного размера, а массив двойных слов – как байтовый массив учетверенного размера. Таким образом, будем обрабатывать только байтовые массивы.

2.3. Подсчёт контрольного кода четности

Для вычисления контрольного кода чётности будем использовать подсчёт битов в исходных элементах массива. С учётом ёмкости контрольного числа в 32 бита для массивов, размер которых не более 32 байта, используем битовое маскирование результирующего кода, а для массивов большего размера – подсчёт байтов, количество битов в которых чётно.

Блок-схема алгоритма имеет вид:

Из блок-схемы видно, что алгоритм подсчета контрольного кода четности использует два вложенных алгоритма: битового маскирования результата и подсчета количества байтов с четным количеством бит.

2.4. Битовое маскирование

Традиционно массивы в графическом виде представляются в виде последовательности элементов, упорядоченных слева направо, а двоичные числа – справа налево:

Такое представление затрудняет понимание общей природы массивов и двоичных чисел. Достаточно упорядочить элементы массива и биты двоичного числа в одном направлении и, возможно, ввести нумерацию элементов массива с 0, чтобы увидеть, что по сути двоичное число – это обычный массив, элементами которого являются биты:

С учётом этого факта несложно построить алгоритм формирования контрольного числа, в котором последовательно будут проверяться элементы массива и в зависимости от результата проверки соответствующие биты контрольного числа будут устанавливаться в 1 или 0. Текстовое описание такого алгоритма:

1. Обнулить контрольное число

2. Установить указатель на последний элемент массива

3. Проверить на четность очередной элемент массива

4. Если чётный, установить флаг переноса в 1. Иначе установить в 0.

5. Выполнить битовый сдвиг контрольного числа с учётом флага переноса на 1 разряд в сторону старших разрядов.

6. Если все элементы массива обработаны, закончить.

7. Иначе перейти к предыдущему элементу массива и продолжить с пункта 3

Графическое представление алгоритма в виде блок-схемы:

2.5. Подсчет в массиве байтов с четным количеством бит

Подсчёт количества байтов с чётным количеством бит реализовать достаточно просто:

Обнулить результат

Установить указатель на первый элемент массива

Проверить на чётность очередной элемент массива

Если чётный, добавить к результату 1

Если все элементы массива обработаны, закончить

Иначе перейти к предыдущему элементу массива и продолжить с пункта 3


Графическое представление алгоритма в виде блок-схемы:

2.6. Проверка элементов массива на чётность

Для проверки отдельных байтов массива на чётность удобно использовать команду test, которая вычисляет результат действия побитового логического «И» над приёмником и источником и устанавливает флаги SF, ZF и PF в соответствии с результатом, при этом результат не сохраняется. Если после выполнения команды test флаг PF будет установлен в 1, количество бит в байте чётно.

1. Вывод на экран текстовых сообщений

Наиболее простое решение – использовать для вывода текста функцию 9hDOS (прерывание INT21h), которая получает адрес строки для вывода через регистр dx, причем строка должна завершаться символом $.

2. Преобразование числа к строковому виду

В качестве основы используем реализацию алгоритма преобразования числа

в десятичное представление. [4, 201]

Суть используемого алгоритма заключается в выполнении следующих действий:

Разделить исходное число на 10.

Добавить к остатку ASCII-код нуля.

Записать полученную цифру в стек.

Увеличить счётчик цифр.

Если ещё есть что делить, продолжить с п.1

По количеству цифр: извлечь цифру из стека и дописать в конец результирующей строки.

Дописать в конец результирующей строки символ $.

Базовый алгоритм рассчитан на работу с 16-разрядными числами. Так как в разрабатываемой программе код чётности будет представлен в виде 32-разрядного числа, модифицируем исходный алгоритм для работы с двойными словами. Такая модификация выполняется достаточно просто заменой в исходном коде наименований регистров: ax на eax, bx на ebx, dx на edx.

3. Ввод числовых данных

С учётом того, что разрабатываемая программа является тестовой и не требует специфического управления клавиатурой, ввод с клавиатуры запрограммируем с помощью функций DOS.

Соответственно, алгоритм ввода числа в виде текстового описания будет выглядеть следующим образом:

Подготовить буфер ввода данных

Вызвать функцию DOS 0Ah для ввода с клавиатуры

Проверить количество введенных символов. Если = 0, ошибка

Выполнить проверку ввода десятичного числа


В целях обеспечения возможности повторного использования, а также для более простого понимания алгоритма в нём выделен отдельный подалгоритм проверки ввода десятичного числа.

4. Алгоритм проверки ввода десятичного числа

Алгоритм проверки ввода десятичного числа можно представить в виде текстового описания:

1) Проверить количество символов. Если больше 5, ошибка

2) Обнулить результат

3) Читать символ из буфера ввода

4) Если код символа меньше «0» или больше «9», ошибка

5) Получить промежуточный результат вычитанием кода символа «0»

6) Умножить на 10 результат

7) Если в ходе умножения получено переполнение, ошибка

8) Прибавить к результату промежуточный результат

9) Если обработаны не все символы, перейти к следующему символу. Переход к п.3

10) Если обработаны все символы, вернуть результат

Приложение

ПРИЛОЖЕНИЕ 1. ЛИСТИНГ ПРОГРАММЫ НА ЯЗЫКЕ ASSEBLER

. modelsmall; модель памяти

. stack 100h; сегмент стека

. data; сегмент данных

MAXDIGITSequ16; максимальное количество символов

; для ввода целого числа

BUFFERSIZEequMAXDIGITS + 2 + 1; объем буфера ввода

bufferdbBUFFERSIZEdup(?) ; буфер ввода

ARRAYSIZEequ4; количество элементов массива / 4

dataArraydb4*ARRAYSIZEdup(?) ; массив данных

changeValueNodb? ; номер элемента массива для изменения

changeValuedb? ; новое значение элемента массива

parityCodedd? ; код четности

; переменные для работы генератора случайных чисел

rand_add69621

rand_mdd7FFFFFFFh

seeddd-1

;

; Сообщения для вывода на экран

;

welcomeMsgdb"Welcome to array parity checker. ", 0Dh, 0Ah

db0Dh, 0Ah

db"This program generates array with random values and calculates its parity code. ", 0Dh, 0Ah

db"Then you can change any array value and program will check parity code. ", 0Dh, 0Ah

db"Enjoy! ", 0Dh, 0Ah

db0Dh, 0Ah

db0Dh, 0Ah, "$"

errorMsgdb"Parity check error. ", 0Dh, 0Ah, "$"

okMsgdb"Parity check ok. ", 0Dh, 0Ah, "$"

dataMsgdb"Array data: $"

codeMsgdb"Parity code: $"

numberMsgdb"Enter array item number to change (0. .15): $"

valueMsgdb"Enter new value (0. .255): $"

uncorrectMsgdb"Incorrect number. $"

writelndb0Dh, 0Ah, "$"

byeMsgdb"Bye! ", 0Dh, 0Ah, "$"

itemSeparatordb" $"

. code; сегмент кода

.386; программа для процессора 80386

; - ----------------------------------------------------------------------------------------

; Главная программа

; - ---------------------------------------------------------------------------------------

start: movax, @data

movds, ax; настройка регистров

moves, ax;

andsp, not 3; выравнивание границы стека

; во избежание ошибки доступа к памяти

movax, 0003h; видеорежим 3, очистка экрана и установка курсора

int10h

movdx, offset welcomeMsg; вывести приветствие

callshowString

callfillArray; заполнить массив случайными данными

movcx, ARRAYSIZE * 4; рассчитать контрольное число

; и записать в parityCode

movsi, offset dataArray

movdi, offset parityCode

callsaveParityCode

callshowArray; вывести значения элементов массива

moveax, parityCode

callshowParityCode

callinputValueNo; запросить у пользователя номер

; элемента массива для изменения

callinputValue; запросить у пользователя новое значение

; элемента массива

callchangeItem; изменить значение элемента массива

callshowArray; вывести значения элементов массива

callgetParityCode; рассчитать контрольное число

callshowParityCode

cmpparityCode, eax

jeparityCode_notChanged

parityCode_Changed:

movdx, offset errorMsg; сообщение об изменении кода четности

callshowString

jmpmain_exit

parityCode_notChanged:

movdx, offset okMsg; сообщение о неизменности кода четности

callshowString

main_exit:

callwriteLine; перевод строки

callwriteLine; перевод строки

movdx, offset byeMsg; до свидания

callshowString

callwriteLine; перевод строки

movax, 4c00h; завершение выполнения программы

int21h

; - ---------------------------------------------------------------------------------------

;

; Заполнить массив случайными данными.

;

; Параметры: нет

;

; Возвращаемое значение: нет

;

; Модификация регистров: нет

;

; Глобальные переменные:

; [ref] dataArray - массив данных для заполнения

; [in] ARRAYSIZE - размер массива

;

; - ---------------------------------------------------------------------------------------

fillArrayproc

pusheax

pushcx

pushedi

movedi, offset dataArray; указатель на массив данных

movcx, ARRAYSIZE; размер массива

fillArray_loop:

callrand; генерировать случайное число в eax

cld; направление записи - вперед

stosd; записать в очередной элемент массива

loopfillArray_loop

popedi

popcx

popeax

ret

fillArrayendp

; - ----------------------------------------------------------------------------------------

; Генерация случайного числа.

;

; Параметры: нет

;

; Возвращаемое значение:

; eax - случайное положительное 32-битное число (от 0 до 2^31 - 2)

;

; Модификация регистров:

; eax

;

; Глобальные переменные:

; [in] rand_a – коэффициент a

; [in] rand_m – коэффициент m

; [ref] seed – последнее случайное число

;

; Примечание:

; Используется алгоритм, описанный в [Зубков С.В.] на стр.238.

; Линейный конгруэнтный генератор описывается формулой:

;

; I [j + 1] = (a * I [j] + c) mod m

;

; При правильно выбранных числах a и c эта последовательность возвращает

; все числа от нуля до m - 1 псевдослучайным образом и ее периодичность

; сказывается только на последовательностях порядка m.

; Классический стандартный генератор Льюиса, Гудмана и Миллера

; использует a = 16807 (7^5) при m = 2^31 - 1.

; Генераторы Парка и Миллера используют a = 48271 и a = 69621

; при том же m.

; Используем последний вариант.

; Значения a и m задаются в глобальных переменных rand_a и rand_m.

; - ---------------------------------------------------------------------------------------

randproc

pushedx

moveax, dword ptr seed; считать последнее случайное число

testeax, eax; проверить его

jsfetch_seed; если не - 1, функция еще ни разу не вызывалась

; и надо создать начальное значение

randomize:

muldword ptr rand_a; умножить на число a

divdword ptr rand_m; взять остаток от деления на 2^31 - 1

moveax, edx

movdword ptr seed, eax; сохранить для следующих вызовов

popedx

ret

fetch_seed:

pushds

push0040h

popds

moveax, dword ptr ds: 006Ch; считать двойное слово из области данных BIOS

; по адресу 0040: 006C - текущее число тактов таймера

popds

jmpshortrandomize

randendp

; - ----------------------------------------------------------------------------------------

; Рассчитать контрольное число элементов массива и сохранить в переменной.

;

; Параметры:

; cx - размер массива

; ds: si - указатель на начало массива

; es: di - указатель на переменную-получатель

;

; Возвращаемое значение: нет

;

; Модификация регистров: нет

; - -----------------------------------------------------------------------------------------

saveParityCodeproc

pusheax

callgetParityCode; рассчитать контрольное число

mov [di], eax; сохранить результат

popeax

ret

saveParityCodeendp

; - ----------------------------------------------------------------------------------------

; Рассчитать контрольное число четности элементов массива.

; Если размер массива больше 32 байт, контрольное число

; рассчитывается методом суммирования - см. getParitySum

; Если размер массива не более 32 байт, контрольное число

; рассчитывается методом битовых масок - см. getParityBits

;

; Параметры:

; cx - размер массива

; ds: si - указатель на начало массива

;

; Возвращаемое значение:

; eax - 32-битное контрольное число

;

; Модификация регистров:

; eax

; - ----------------------------------------------------------------------------------------

getParityCodeproc

cmpcx, 32

jagetParityCode_sum

callgetParityBits

ret

getParityCode_sum:

callgetParitySum

ret

getParityCodeendp

; - -----------------------------------------------------------------------------------------

; Рассчитать контрольное число четности элементов массива методом битовых масок.

; Используется для массивов размером не более 32 байт.

; Для каждого байта определяется количество битов. Если оно четное, соответствующий

; бит контрольного числа устанавливается в 1, если нечетное - в 0.

; Нулевому байту массива соответствует нулевой бит контрольного числа и т.д.

;

; Параметры:

; cx - размер массива

; ds: si - указатель на начало массива

;

; Возвращаемое значение:

; eax - 32-битное контрольное число

;

; Модификация регистров:

; eax

; - ----------------------------------------------------------------------------------------

getParityBitsproc

pushebx

pushcx

pushsi

xorebx, ebx; обнулить результат

std; направление чтения - назад

addsi, cx; установить указатель на последний элемент массива

decsi

getParityBits_loop:

lodsb; прочитать байт данных в al

testal, al; проверить четность

jpgetParityBits_parity; если четность, перейти к установке флага cf

clc; сброс флага cf

jmpshort getParityBits_shift; перейти к формированию результата

getParityBits_parity:

stc; установить флаг cf

getParityBits_shift:

rclebx, 1; сдвиг влево на 1 бит с учетом флага cf

loopgetParityBits_loop

moveax, ebx; записать результат в eax

popsi

popcx

popebx

ret

getParityBitsendp

; - -----------------------------------------------------------------------------------------

; Рассчитать контрольное число четности элементов массива суммированием.

; Используется для массивов размером более 32 байт.

; Для каждого байта определяется количество битов. Если оно четное,

; контрольное число увеличиваем на 1.

;

; Параметры:

; cx - размер массива

; ds: si - указатель на начало массива

;

; Возвращаемое значение:

; eax - 32-битное контрольное число

;

; Модификация регистров:

; eax

;

; - ----------------------------------------------------------------------------------------

getParitySumproc

pushebx

pushcx

pushsi

xorebx, ebx; обнулить результат

cld; направление чтения - вперед

getParitySum_loop:

lodsb; прочитать байт данных в al

testal, al; проверить четность

jnpgetParitySum_next; если не четность, продолжить

incebx; увеличить результат на 1

getParitySum_next:

loopgetParitySum_loop

moveax, ebx; записать результат в eax

popsi

popcx

popebx

ret

getParitySumendp

; - -----------------------------------------------------------------------------------------

; Вывод на экран элементов массива.

;

; Параметры: нет

;

; Возвращаемое значение: нет

;

; Модификация регистров: нет

;

; Глобальные переменные:

; [in] dataMsg – сообщение

; [in] dataArray – массив данных

; [ref] buffer – буфер преобразования числа в строку

; [in] itemSeparator – разделитель элементов массива

; [in] ARRAYSIZE - размер массива

; - ----------------------------------------------------------------------------------------

showArrayproc

pusheax

pushcx

pushdx

pushsi

pushdi

movdx, offset dataMsg; сообщение

callshowString

xoreax, eax; обнулить аккумулятор

movsi, offsetdataArray; читать данные из массива данных

movdi, offsetbuffer

movcx, ARRAYSIZE * 4; размер массива, байт

showArray_loop:

cld; направление чтения - вперед

lodsb; прочитать байт данных в al

callint2dec; преобразовать в строку

movdx, offset buffer

callshowString; вывести на экран

movdx, offset itemSeparator

callshowString; вывести пробел

loopshowArray_loop

callwriteLine; перевод строки

popdi

popsi

popdx

popcx

popeax

ret

showArrayendp

; - ---------------------------------------------------------------------------------------

; Вывод на экран контрольного кода четности.

;

; Параметры:

; eax - контрольное число

;

; Возвращаемое значение: нет

;

; Модификация регистров: нет

;

; Глобальные переменные:

; [in] codeMsg – сообщение

; [ref] buffer – буфер преобразования числа в строку

; - -----------------------------------------------------------------------------------------

showParityCodeproc

pushdx

pushdi

movdx, offsetcodeMsg; сообщение

callshowString

movdi, offset buffer

callint2dec; преобразовать в строку

movdx, di

callshowString; вывести на экран

callwriteLine; перевод строки

popdi

popdx

ret

showParityCodeendp

; - ----------------------------------------------------------------------------------------

; Запросить у пользователя номер элемента массива для изменения.

;

; Параметры: нет

;

; Возвращаемое значение: нет

;

; Модификация регистров: нет

;

; Глобальные переменные:

; [in] ARRAYSIZE - размер массива

; [in] numberMsg – запрос на ввод номера элемента массива

; [in] uncorrectMsg – сообщение об ошибке

; [out] changeValueNo – результат ввода

; - ----------------------------------------------------------------------------------------

inputValueNoproc

pushbx

pushcx

pushdx

pushsi

pushdi

movbx, ARRAYSIZE * 4 - 1; максимально допустимое значение

movcl, 2; максимально допустимое количество символов

movdx, offset numberMsg; запрос на ввод номера элемента массива

movsi, offset uncorrectMsg; сообщение об ошибке

movdi, offset changeValueNo; запомнить результат ввода в changeValueNo

callinputNumber

popdi

popsi

popdx

popcx

popbx

ret

inputValueNoendp

; - -----------------------------------------------------------------------------------------

; Запросить у пользователя новое значение элемента массива.

;

; Параметры: нет

;

; Возвращаемое значение: нет

;

; Модификация регистров: нет

;

; Глобальные переменные:

; [in] valueMsg - запрос на ввод нового значения элемента массива

; [in] uncorrectMsg – сообщение об ошибке

; [out] changeValue – результат ввода

; - -----------------------------------------------------------------------------------------

inputValueproc

pushbx

pushcx

pushdx

pushsi

pushdi

movbx, 255; максимально допустимое значение

movcl, 3; максимально допустимое количество символов

movdx, offset valueMsg; запрос на ввод нового значения элемента массива

movsi, offset uncorrectMsg; сообщение об ошибке

movdi, offset changeValue; запомнить результат ввода в changeValue

callinputNumber

popdi

popsi

popdx

popcx

popbx

ret

inputValueendp

; - -----------------------------------------------------------------------------------------

; Изменить значение элемента массива.

;

; Параметры: нет

;

; Возвращаемое значение: нет

;

; Модификация регистров: нет

;

; Глобальные переменные:

; [ref] dataArray – массив данных

; [in] changeValueNo – номер элемента массива для изменения

; [in] changeValue – новое значение элемента массива

; - -----------------------------------------------------------------------------------------

changeItemproc

pushax

pushbx

pushsi

movbx, offset dataArray

xorax, ax

moval, changeValueNo

movsi, ax

moval, changeValue

mov [bx + si], al

popsi

popbx

popax

ret

changeItemendp

; - ----------------------------------------------------------------------------------------

; Запрос у пользователя числа.

; Вводятся беззнаковые целые числа в диапазоне 0. .65535.

;

; Параметры:

; bx - максимально допустимое значение

; cl - максимально допустимое количество символов

; dx - указатель на строку-приглашение для ввода

; si - указатель на сообщение об ошибке

; di - указатель на байтовую переменную-получатель

;

; Возвращаемое значение: нет

;

; Модификация регистров: нет

;

; Глобальные переменные:

; [ref] buffer – буфер преобразования строки в число

; - -----------------------------------------------------------------------------------------

inputNumberproc

pushax

pushdi

inputNumber_input:

callshowString; вывод строки-приглашения для ввода

movdi, offset buffer; указатель на буфер ввода

calldo_inputNumber

callwriteLine; перевод строки

jncinputNumber_exit; если нет ошибки ввода, выход

inputNumber_error:

pushdx

movdx, si; сообщение об ошибке

callshowString

popdx

jmpshort inputNumber_input

inputNumber_exit:

popdi

mov [di], al; запомнить результат ввода в переменной-получателе

popax

ret

inputNumberendp

; - -----------------------------------------------------------------------------------------

; Ввод числа.

; Вводятся беззнаковые целые числа в диапазоне 0. .65535.

;

; Параметры:

; bx - максимально допустимое значение

; cl - максимально допустимое количество символов

; es: di - указатель на буфер ввода

; первый байт буфера резервируется для записи максимально допустимого количества символов

; второй байт буфера резервируется для записи количества реально введенных символов

;

; Возвращаемое значение:

; ax - результат ввода

; ch - количество введенных символов

; cf -

; = 0 в случае успешного преобразования

; = 1 в случае ошибки преобразования

;

; Модификация регистров:

; ax, cx, flags. cf

; - -----------------------------------------------------------------------------------------

do_inputNumberproc

pushdx

pushsi

andcx, 0Fh; обнуление ch (длины введенной строки)

clc; сброс флага ошибки

inccl

mov [di], cl; максимальное количество символов для ввода

deccl

movdx, di; настройка указателя на начало буфера ввода

movah, 0Ah; ввод с клавиатуры

int21h

movch, [di + 1] ; количество введенных символов

cmpch, 0; если = 0, ошибка

jedo_inputNumber_error1

movsi, di; подготовим указатель на первый введенный символ

incsi; для последующего преобразования строки в число

incsi

pushcx; преобразование десятичного числа

movcl, ch

andcx, 0Fh

calldec2int

popcx

jcdo_inputNumber_error1; если ошибка преобразования, выход с ошибкой

cmpbx, ax

jcdo_inputNumber_error2; если превышение лимита, выход с ошибкой

; без очистки результата

jmpdo_inputNumber_exit; если не превышает лимит, выход без ошибки

do_inputNumber_error1: ; ошибка преобразования

xorax, ax; обнулить результат

do_inputNumber_error2: ; ошибка преобразования

stc; установить флаг ошибки

do_inputNumber_exit:

popsi

popdx

ret

do_inputNumberendp

; - -----------------------------------------------------------------------------------------

; Вывод строки на экран.

;

; Параметры:

; dx - адрес строки для вывода, строка должна заканчиваться символом $

;

; Возвращаемое значение: нет

;

; Модификация регистров: нет

; - ----------------------------------------------------------------------------------------

showStringproc

pushax

movah, 9h; вызов функции DOS

int21h

popax

ret

showStringendp

; - -----------------------------------------------------------------------------------------

; Перевод строки.

;

; Параметры: нет

;

; Возвращаемое значение: нет

;

; Модификация регистров: нет

;

; Глобальные переменные:

; [in] writeln – коды перевода строки

; - -----------------------------------------------------------------------------------------

writeLineproc

pushdx

movdx, offset writeln; вывод символов перевода строки

callshowString

popdx

ret

writeLineendp

; - -----------------------------------------------------------------------------------------

; Преобразование строки, содержащей десятичные символы, в число.

; Строка должна содержать строковое представление целого числа в диапазоне 0. .65535.

;

; Параметры:

; ds: si - указатель на первый обрабатываемый символ исходной строки

; cx - количество символов (беззнаковое число)

;

; Возвращаемое значение:

; ax - результат преобразования

; cf -

; = 0 в случае успешного преобразования

; = 1 в случае ошибки преобразования

;

; Модификация регистров:

; ax, flags. cf

; - -----------------------------------------------------------------------------------------

dec2intproc

pushbx

pushcx

pushdx

pushsi

cmpcx, 0; проверка: количество символов 1. .5

jedec2int_error

cmpcx, 5

jadec2int_error

xorax, ax; обнуление результата

xorbx, bx; обнуление регистра-приемника

clc; сброс флага ошибки

dec2int_loop: ; цикл обработки символов исходной строки

movbl, byte ptr [si] ; читать очередной символ

cmpbl, '0'; если меньше 0, ошибка

jbdec2int_error

cmpbl, '9'; если больше 9, ошибка

jadec2int_error

subbl, '0'; вычесть код символа 0

movdx, ax; умножение на 10 содержимого ax:

shlax, 1; ax = 2x

jcdec2int_error

shlax, 1; ax = 4x

jcdec2int_error

addax, dx; ax = 4x + x = 5x

jcdec2int_error

shlax, 1; ax = 10x

jcdec2int_error

addax, bx; добавить промежуточный результат преобразования

jcdec2int_error

incsi; перейти к следующему символу

loopdec2int_loop

jmpdec2int_exit

dec2int_error: ; ошибка преобразования

xorax, ax; обнулить результат

stc; установить флаг ошибки

dec2int_exit:

popsi

popdx

popcx

popbx

ret

dec2intendp

; - ----------------------------------------------------------------------------------------

; Преобразование числа в десятичное строковое представление.

; Полученная строка завершается символом $.

;

; Параметры:

; eax - исходное число

; es: di - указатель на первый символ буфера для выходной строки

;

; Возвращаемое значение:

; выходная строка

;

; Модификация регистров: нет

; - ----------------------------------------------------------------------------------------

int2decproc

pusheax

pushebx

pushcx

pushedx

pushdi

xorebx, ebx

movbl, 10; множитель

xorcx, cx; обнуление счетчика символов

int2dec_loop: ; начало цикла преобразования

xoredx, edx; обнуление промежуточного результата преобразования

divebx; деление ax на 10, в dl - остаток от деления

adddl, '0'; перевод в ASCII

pushdx; сохранение результата в стеке

inccx; увеличить счетчик символов

testeax, eax; проверить ax на 0

jnzint2dec_loop; если что-то осталось,

; продолжить цикл преобразования

cld; направление обработки строк - вперед

int2dec_store: ; цикл формирования конечного результата

popax; восстановить цифру из стека

stosb; записать в результат

loopint2dec_store; проверка окончания цикла

movbyte ptr [di], '$'; добавить символ завершения строки

popdi

popedx

popcx

popebx

popeax

ret

int2decendp

; - -------------------------------------------------------------------------------------- - end start; конец программы

; - ---------------------------------------------------------------------------------------

Литература

1. Бойко В.И. и др. Схемотехника электронных систем. Микропроцессоры и микроконтроллеры. – СПб.: БХВ-Петербург, 2004. .

2. Гутников В.С. Интегральная электроника в измерительных устройствах.2-е изд., перераб. и доп. – Л.: Энергоатомиздат. Ленигр. отд-ние, 1988.

3. Джордейн Р. Справочник программиста персональных компьютеров типа IBMPC, XT и AT. – М.: Финансы и статистика, 1992

4. Зубков С.В. Assembler для DOS, Windows и UNIX. – М.: ДМК Пресс, 2000.

5. Кулаков В. Программирование на аппаратном уровне. Специальный справочник. – СПб: Питер, 2001.

6. Мячев А.А., Степанов В.Н. Персональные ЭВМ и микроЭВМ. Основы организации: Справочник / Под ред.А. А. Мячева. – М.: Радио и связь, 1991.

7. Использование TurboAssembler при разработке программ. – Киев: «Диалектика», 1994

8. Фролов А.В., Фролов Г.В. Операционная система MSDOS. – М.: «Диалог-МИФИ», 1992

9. Юров В.И. Assembler. – СПб: Питер, 2000

10. http: // www. gelezo. com

ОТКРЫТЬ САМ ДОКУМЕНТ В НОВОМ ОКНЕ

Комментариев на модерации: 2.

ДОБАВИТЬ КОММЕНТАРИЙ [можно без регистрации]

Ваше имя:

Комментарий