-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfloat.asm
458 lines (360 loc) · 11.9 KB
/
float.asm
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
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
; calculate equation with high precision without math coprocessor
; this program calculates linear equation: ax + b = 0
; the result is printed with floating point.
; for example: a = 7, b = 2
; x = -0.28571428....
name "float"
precision = 30 ; max digits after the dot.
dseg segment 'data'
cr equ 0Dh
lf equ 0Ah
new_line equ 0Dh,0Ah, '$'
mess0 db 'calculation of ax + b = 0', new_line
mess1 db 'enter a (-32768..32767)!', new_line
mess2 db lf, cr, 'enter b (-32768..32767)!', new_line
mess3 db cr, lf, cr, lf, 'data:', '$'
mess4 db cr, lf, ' a = ', '$'
mess5 db cr, lf, ' b = ', '$'
mess6 db cr, lf, 'result: ', cr, lf, ' x = ', '$'
mess7 db cr, lf, cr, lf, 'no solution!', new_line
mess8 db cr, lf, cr, lf, 'infinite number of solutions!', new_line
error db cr, lf, 'the number is out of range!', new_line
twice_nl db new_line, new_line
make_minus db ? ; used as a flag in procedures.
a dw ?
b dw ?
ten dw 10 ; used as multiplier.
four dw 4 ; used as divider.
dseg ends
sseg segment stack 'stack'
dw 100h dup(?)
sseg ends
cseg segment 'code'
;*******************************************************************
start proc far
; store return address to os:
push ds
xor ax, ax
push ax
; set segment registers:
mov ax, dseg
mov ds, ax
mov es, ax
; welcome message:
lea dx, mess0
call puts ; display the message.
; ask for 'a' :
lea dx, mess1
call puts ; display the message.
call scan_num ; input the number into cx.
mov a, cx
; ask for 'b' :
lea dx, mess2
call puts ; display the message.
call scan_num ; input the number into cx.
mov b, cx
; print the data:
lea dx, mess3
call puts
lea dx, mess4
call puts
mov ax, a
call print_num ; print ax.
lea dx, mess5
call puts
mov ax, b
call print_num ; print ax.
; check data:
cmp a, 0
jne soluble ; jumps when a<>0.
cmp b, 0
jne no_solution ; jumps when a=0 and b<>0.
jmp infinite ; jumps when a=0 and b=0.
soluble:
; calculate the solution:
; ax + b = 0 -> ax = -b -> x = -b/a
neg b
mov ax, b
xor dx, dx
; check the sign, make dx:ax negative if ax is negative:
cmp ax, 0
jns not_singned
not dx
not_singned:
mov bx, a ; divider is in bx.
; '-b' is in dx:ax.
; 'a' is in bx.
idiv bx ; ax = dx:ax / bx (dx - remainder).
; 'x' is in ax.
; remainder is in dx.
push dx ; store the remainder.
lea dx, mess6
call puts
pop dx
; print 'x' as float:
; ax - whole part
; dx - remainder
; bx - divider
call print_float
jmp end_prog
no_solution:
lea dx, mess7
call puts
jmp end_prog
infinite:
lea dx, mess8
call puts
end_prog:
lea dx, twice_nl
call puts
; wait for any key....
mov ah, 0
int 16h
ret
start endp
;***************************************************************
; prints number in ax and it's fraction in dx.
; used to print remainder of 'div/idiv bx'.
; ax - whole part.
; dx - remainder.
; bx - the divider that was used to get the remainder from divident.
print_float proc near
push cx
push dx
; because the remainder takes the sign of divident
; its sign should be inverted when divider is negative
; (-) / (-) = (+)
; (+) / (-) = (-)
cmp bx, 0
jns div_not_signed
neg dx ; make remainder positive.
div_not_signed:
; print_num procedure does not print the '-'
; when the whole part is '0' (even if the remainder is
; negative) this code fixes it:
cmp ax, 0
jne checked ; ax<>0
cmp dx, 0
jns checked ; ax=0 and dx>=0
push dx
mov dl, '-'
call write_char ; print '-'
pop dx
checked:
; print whole part:
call print_num
; if remainder=0, then no need to print it:
cmp dx, 0
je done
push dx
; print dot after the number:
mov dl, '.'
call write_char
pop dx
; print digits after the dot:
mov cx, precision
call print_fraction
done:
pop dx
pop cx
ret
print_float endp
;***************************************************************
; prints dx as fraction of division by bx.
; dx - remainder.
; bx - divider.
; cx - maximum number of digits after the dot.
print_fraction proc near
push ax
push dx
next_fraction:
; check if all digits are already printed:
cmp cx, 0
jz end_rem
dec cx ; decrease digit counter.
; when remainder is '0' no need to continue:
cmp dx, 0
je end_rem
mov ax, dx
xor dx, dx
cmp ax, 0
jns not_sig1
not dx
not_sig1:
imul ten ; dx:ax = ax * 10
idiv bx ; ax = dx:ax / bx (dx - remainder)
push dx ; store remainder.
mov dx, ax
cmp dx, 0
jns not_sig2
neg dx
not_sig2:
add dl, 30h ; convert to ascii code.
call write_char ; print dl.
pop dx
jmp next_fraction
end_rem:
pop dx
pop ax
ret
print_fraction endp
;***************************************************************
; this procedure prints number in ax,
; used with print_numx to print "0" and sign.
; this procedure also stores the original ax,
; that is modified by print_numx.
print_num proc near
push dx
push ax
cmp ax, 0
jnz not_zero
mov dl, '0'
call write_char
jmp printed
not_zero:
; the check sign of ax,
; make absolute if it's negative:
cmp ax, 0
jns positive
neg ax
mov dl, '-'
call write_char
positive:
call print_numx
printed:
pop ax
pop dx
ret
print_num endp
;***************************************************************
; prints out a number in ax (not just a single digit)
; allowed values from 1 to 65535 (ffff)
; (result of /10000 should be the left digit or "0").
; modifies ax (after the procedure ax=0)
print_numx proc near
push bx
push cx
push dx
; flag to prevent printing zeros before number:
mov cx, 1
mov bx, 10000 ; 2710h - divider.
; check if ax is zero, if zero go to end_show
cmp ax, 0
jz end_show
begin_print:
; check divider (if zero go to end_show):
cmp bx,0
jz end_show
; avoid printing zeros before number:
cmp cx, 0
je calc
; if ax<bx then result of div will be zero:
cmp ax, bx
jb skip
calc:
xor cx, cx ; set flag.
xor dx, dx
div bx ; ax = dx:ax / bx (dx=remainder).
; print last digit
; ah is always zero, so it's ignored
push dx
mov dl, al
add dl, 30h ; convert to ascii code.
call write_char
pop dx
mov ax, dx ; get remainder from last div.
skip:
; calculate bx=bx/10
push ax
xor dx, dx
mov ax, bx
div ten ; ax = dx:ax / 10 (dx=remainder).
mov bx, ax
pop ax
jmp begin_print
end_show:
pop dx
pop cx
pop bx
ret
print_numx endp
;***************************************************************
; displays the message (dx-address)
puts proc near
push ax
mov ah, 09h
int 21h
pop ax
ret
puts endp
;*******************************************************************
; reads char from the keyboard into al
; (modifies ax!!!)
read_char proc near
mov ah, 01h
int 21h
ret
read_char endp
;***************************************************************
; gets the multi-digit signed number from the keyboard,
; result is stored in cx. backspace is not supported, for backspace
; enabled input function see c:\emu8086\inc\emu8086.inc
scan_num proc near
push dx
push ax
xor cx, cx
; reset flag:
mov make_minus, 0
next_digit:
call read_char
; check for minus:
cmp al, '-'
je set_minus
; check for enter key:
cmp al, cr
je stop_input
; multiply cx by 10 (first time the result is zero)
push ax
mov ax, cx
mul ten ; dx:ax = ax*10
mov cx, ax
pop ax
; check if the number is too big
; (result should be 16 bits)
cmp dx, 0
jne out_of_range
; convert from ascii code:
sub al, 30h
; add al to cx:
xor ah, ah
add cx, ax
jc out_of_range ; jump if the number is too big.
jmp next_digit
set_minus:
mov make_minus, 1
jmp next_digit
out_of_range:
lea dx, error
call puts
stop_input:
; check flag:
cmp make_minus, 0
je not_minus
neg cx
not_minus:
pop ax
pop dx
ret
scan_num endp
;***************************************************************
; prints out single char (ascii code should be in dl)
write_char proc near
push ax
mov ah, 02h
int 21h
pop ax
ret
write_char endp
;***************************************************************
cseg ends
end start