;
; Примечание:
; Используется алгоритм, описанный в [Зубков С.В.] на стр.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 - указатель на буфер ввода
; первый байт буфера резервируется для записи максимально допустимого количества символов