Смекни!
smekni.com

Микропроцессор i8086/i8088 (стр. 3 из 6)

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

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

Если размер массива не превышает ёмкости контрольного кода (количеству бит в двоичном представлении числа), то каждому элементу массива можно поставить в соответствие один бит в контрольном коде. При этом если элемент массива чётный, то соответствующий бит контрольного кода будем устанавливать в 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 разряда). Если принять во внимание, что в любом случае под массив отводится непрерывная область памяти, то массив машинных слов можно рассматривать как байтовый массив двойного размера, а массив двойных слов – как байтовый массив учетверенного размера. Таким образом, будем обрабатывать только байтовые массивы.