-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprog.asm
More file actions
274 lines (231 loc) · 13.6 KB
/
prog.asm
File metadata and controls
274 lines (231 loc) · 13.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
use16 ; Генерировать 16-битный код
org 100h ; Программу начать с сотой й строки
mov cx, [size] ; Счетчик цикла
lp1:
mov bx, [arr+si] ; Поместить в регистр bx следующее (или первое) значение элемента массива
add bx, 0 ; Прибавить 0 к bx, для переключения флага Z
jz nul ; Переход на метку nul, в случае, когда флаг Z=1
jmp iter1 ; Переход на метку iter, в случае, когда флаг Z=0
nul:
mov [zero], di ; Внести в переменную текущий индекс массива
iter1:
add si, 2 ; Переход к следующему элементу массива
add di, 1 ; Увеличение значения индекса массива
loop lp1 ; Возврат в начало массива
cmp [zero], -1 ; Если значение zero не изменилось, т.е. нулей нет, то переход к сортировке
jz sort
add [arr+si-2], 0 ; Если последний элемент массива не равен 0, переход к следующему циклу. Иначе вывод сообщения
jz outputEnd
mov al, 2 ; Подготовка к умножению
mul [zero] ; Получение началального значения регистра si, равного индексу последнего нулевого значения (увеличенный в два раза)
mov si, ax ; Запись начального значения
add si, 2 ; Увеличение начального значения регистра si на следующий после нулевого элемент
mov cx, [size] ; Поместить размер массива в счетчик
sub cx, [zero] ; Установить счетчик в значение равное количеству оставшихся после последнего нуля единиц
dec cl
lp2:
mov bx, [arr+si] ; Поместить в регистр bx значение элемента массива
test bx, 1 ; Проверка на четность
jnp sum ; Переход, если нечетное
jmp iter2; Переход, если не нечетное
sum:
add [sum1], bx ; Прибавить к переменной текущее значение нечетного элемента массива
iter2:
add si, 2 ; Переход к следующему элементу массива
loop lp2 ; Возврат в начало массива
jmp checkStart
outputEnd:
mov dx, zeroEnd ; Поместить в регистр адрес строки, оповещающей о том, что ноль в конце
mov ax, 900h ; Поместить в регистр номер функции (вывод сообщения)
int 21h ; Вызов функции
mov bx,print_endline ;Адрес процедуры print_endline
call bx ;Вывод конца строки
checkStart:
add [zero], 0 ; Проверка, равен ли первый элемент массива 0. Если да - переход
jz outputStart
mov ax, 2 ; Подготовка к умножению
mul [zero] ; Получение началального значения регистра si, равного индексу последнего нулевого значения (увеличенный в два раза)
mov si, ax ; Запись начального значения
sub si, 2 ; Уменьшение начального значения регистра si на следующий после нулевого элемент
mov cx, [zero] ; Поместить количество элементов в массиве до нулевого значения в счетчик
lp3:
mov bx, [arr+si] ; Поместить в регистр bx значение элемента массива
add bx, 0 ; Добавить ноль, для переключения флага Z, в случае, если элемент является нулем.
jz iter3 ; Перейти к следующей итерации, в случае, если элемент является нулем
test bx, 1 ; Проверка на четность
jp avg ; Переход, если четное
jmp iter3 ; Переход, если не четное
avg:
add [avgs], bx ; Прибавить к сумме четных элементов
add [avgc], 1 ; Прибавить количество четных элементов
iter3:
sub si, 2 ; Переход к предыдущему элементу масива
loop lp3 ; Возврат в начало массива
add [avgs], 0 ; Проверка, равна ли сумма четных элементов нулю, если да, то деление не начинать
jz exit ; Пропуск деления, если арифметическое не может вычислиться (деление на ноль)
mov ax, [avgs] ; Поместить в регистр ax сумму четных чисел
mov bx, [avgc] ; Поместить в регистр bl количество четных чисел
add ax, 0 ; Проверка на отрицательное число
jns posit ; Если число не отрицательное, то переход к обычному делению
neg ax ; Переход от отрицательного к положительному
idiv bx ; Выполнение деления
neg ax ; Возврат к отрицательному виду числа
mov [avgs], ax
jmp exit ; Пропуск сортировки
posit:
idiv bx ; Получить среднее арифметическое значение четных чисел
mov [avgs], ax
jmp exit ; Пропуск сортировки
outputStart:
mov dx, zeroStart ; Поместить в регистр адрес строки, оповещающей о том, что ноль в конце
mov ax, 900h ; Поместить в регистр номер функции (вывод сообщения)
int 21h ; Вызов функции
mov bx,print_endline ;Адрес процедуры print_endline
call bx ;Вывод конца строки
jmp exit ; Пропуск сортировки
sort:
mov cx, [size] ; Счетчик цикла
dec cl ; Уменьшить цикл на 1, чтобы не выходить за рамки в случае, когда используется cl+1
mov si, 0
lp4:
mov di, si ; Для внутреннего цикла
add di, 2 ; Для внутреннего цикла (следующий элемент в массиве, после текущего)
mov dx, si ; Поместить в регистр значение текущего элемента массива. В случае, если во внутреннему цикле не будет найдено значение больше текущего, значение регистра не изменится
push cx ; Буфер для сохранения числа текущих итераций внешнего цикла
mov bx, [arr+si] ; Буфер для максимального значения, равный индексу текущего элемента массива
lp5:
cmp [arr+di], bx ; Сравнить, больше ли значение следующего элемента массива, чем первоначальное
jg max ; Переход, если больше
jmp iter5 ; Переход, если не больше
max:
mov bx, [arr+di] ; Буфер для индекса максимального значения
mov dx, di ; Изменить значение регистра на номер элемента в массиве, которой больше, чем первоначальный
iter5:
add di, 2 ; Переход к следующему элементу внутреннего цикла
loop lp5
mov di, dx ; Поместить в регистр номер элемента, который нужно заменить
mov dx, [arr+si] ; Поместить в регистр текущее значение элемента (буфер)
mov [arr+si], bx ; Поместить на место текущего значения массива, значение большее
mov [arr+di], dx ; Поместить на место элемента, который нужно заменить, значение буфера
pop cx ; Восстановить число итераций внешнего цикла из буфера
add si, 2 ; Перейти к следующему элементу массива
loop lp4
exit:
mov ax, [sum1]
mov di, outputSUM
mov cx,print_str ;Адрес процедуры print_str
mov bx,print_endline ;Адрес процедуры print_endline
call cx ;Вывод строки
call print_word_sdec ;Вывод AX в десятичном виде (со знаком)
call bx ;Вывод конца строки
mov ax, [avgs]
mov di, outputAVG
mov cx,print_str ;Адрес процедуры print_str
mov bx,print_endline ;Адрес процедуры print_endline
call cx ;Вывод строки
call print_word_sdec ;Вывод AX в десятичном виде (со знаком)
call bx ;Вывод конца строки
mov di, outputMAS
mov cx,print_str ;Адрес процедуры print_str
call cx ;Вывод строки
mov cx, [size] ; Счетчик цикла
mov si, 0
lpmas:
push cx
mov ax, [arr+si]
call print_word_sdec ;Вывод AX в десятичном виде (со знаком)
cmp cx, 1
jz noncom
mov ah,9
mov dx, comma
int 21h
noncom:
add si, 2 ; Переход к следующему элементу массива
pop cx
loop lpmas ; Возврат в начало массива
mov ax,4C00h ;
int 21h ;
print_word_udec:
push di
mov di,buffer ;DI = адрес буфера
push di ;Сохранение DI в стеке
call word_to_udec_str ;Преобразование слова в AX в строку
mov byte[di],'$' ;Добавление символа конца строки
pop di ;DI = адрес начала строки
call print_str ;Вывод строки на консоль
pop di
ret
print_str:
push ax
mov ah,9 ;Функция DOS 09h - вывод строки
xchg dx,di ;Обмен значениями DX и DI
int 21h ;Обращение к функции DOS
xchg dx,di ;Обмен значениями DX и DI
pop ax
ret
print_endline:
push di
mov di,endline ;DI = адрес строки с символами CR,LF
call print_str ;Вывод строки на консоль
pop di
ret
print_word_sdec:
push di
mov di,buffer ;DI = адрес буфера
push di ;Сохранение DI в стеке
call word_to_sdec_str ;Преобразование слова в AX в строку
mov byte[di],'$' ;Добавление символа конца строки
pop di ;DI = адрес начала строки
call print_str ;Вывод строки на консоль
pop di
ret
word_to_sdec_str:
push ax
test ax,ax ;Проверка знака AX
jns wtsds_no_sign ;Если >= 0, преобразуем как беззнаковое
mov byte[di],'-' ;Добавление знака в начало строки
inc di ;Инкремент DI
neg ax ;Изменение знака значения AX
wtsds_no_sign:
call word_to_udec_str ;Преобразование беззнакового значения
pop ax
ret
word_to_udec_str:
push ax
push cx
push dx
push bx
xor cx,cx ;Обнуление CX
mov bx,10 ;В BX делитель (10 для десятичной системы)
wtuds_lp1: ;Цикл получения остатков от деления
xor dx,dx ;Обнуление старшей части двойного слова
div bx ;Деление AX=(DX:AX)/BX, остаток в DX
add dl,'0' ;Преобразование остатка в код символа
push dx ;Сохранение в стеке
inc cx ;Увеличение счетчика символов
test ax,ax ;Проверка AX
jnz wtuds_lp1 ;Переход к началу цикла, если частное не 0.
wtuds_lp2: ;Цикл извлечения символов из стека
pop dx ;Восстановление символа из стека
mov [di],dl ;Сохранение символа в буфере
inc di ;Инкремент адреса буфера
loop wtuds_lp2 ;Команда цикла
pop bx
pop dx
pop cx
pop ax
ret
endline db 13,10,'$'
buffer rb 7
outputAVG db 'average : $'
outputSUM db 'sum : $'
outputMAS db 'array : $'
comma db ', $'
size dw 7
zero dw -1
sum1 dw 0
avgs dw 0
avgc dw 0
arr dw -10, 4, 0, 31, 0, 9, 8
zeroEnd db 'Zero in the end$'
zeroStart db 'Zero in the start$'