-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcalc.asm
417 lines (386 loc) · 9.18 KB
/
calc.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
TITLE Fancy Calculator
PAGE 60,132
;
;
;Created by Eric Wilson on or about 12/01/2015
;
;Define constants
CR EQU 0DH ;define carriage return
LF EQU 0AH ;define line feed
EOT EQU '$' ;define end of text marker
;
JMP START ;Jump to that startsssss
;
;What's a variable?
;
INFOP: DB LF,CR,"***********~FANCY CALCULATOR~*************"
DB LF,CR,"| By: Eric Wilson |"
DB LF,CR,"| Evaluates simple 8-bit mathematical |"
DB LF,CR,"| expressions with pinpoint integer |"
DB LF,CR,"| accuracy faster than Einstein's smart |"
DB LF,CR,"| brother! |"
DB LF,CR,"| Supports [+,-,*,/] and non-negative |"
DB LF,CR,"| operands. |"
DB LF,CR,"| |"
DB LF,CR,"******************************************"
DB LF,LF,CR,EOT
;
IFORM: DB LF,CR," "
PROMP: DB LF,CR,"Please express yourself mathematicallly:"
DB LF,CR,EOT
INBUF DB " "
DB LF,CR,EOT
OPND1: DB 203 ;operand storage
OPND2: DB 5 ;operand storage
OPRTR: DB "*" ;operator storage
RESLT: DB " ",EOT ;5 bytes reserved for ascii result
RMNDR: DB " ",EOT ;5 bytes reserved for ascii remainder
RSSTR: DB LF,CR,"Result: ",EOT
RMSTR: DB "Remndr: ",EOT
OPST1: DB "000"
OPST2: DB "000"
START:
;print info panel
MOV AH, 09H
LEA DX,INFOP
INT 21H
STRT1:
;reset memory values
MOV B[RMNDR]," " ;reset remainder to check for division
;CALL INRST ;reset input buffer
;prompt user input
MOV AH,09H
LEA DX,PROMP
INT 21H
;TODO get user input
MOV AH,0AH
MOV DX,OFFSET INBUF
INT 21H
;TODO parse user input
CALL PARSE
;DEBUG
;CALL VALUS
;PREPARE VALUES FOR CALCULATION!!!
LEA SI,OPST1
CALL A2B8
MOV B[OPND1],AL
LEA SI,OPST2
CALL A2B8
MOV B[OPND2],AL
;call calculation subroutine
CALL CALC
;Remove leading 0s from result
LEA SI,RESLT
CALL LDZRO
;Print result string
MOV AH, 09H
LEA DX,RSSTR
INT 21H
;Print result
MOV AH, 09H
LEA DX,RESLT
INT 21H
;special for division
LEA SI,RMNDR
CMP B[SI],"0" ;if remainder has been modified
JE PRTRM ;jump to print remainder
EXSTR:
;exit
CALL EXIT
PRTRM:
;next line
MOV AH,02H
MOV DL,LF
INT 21H
MOV AH,02H
MOV DL,CR
INT 21H
;remove leading 0s from remainder
LEA SI,RMNDR
CALL LDZRO
;Print remainder string
MOV AH, 09H
LEA DX,RMSTR
INT 21H
;Print remainder
MOV AH, 09H
LEA DX, RMNDR
INT 21H
CALL EXIT
;***************************************************************
PARSE:
LEA SI,INBUF + 2 ;point SI at beginning of
;user input
;get first operand
MOV AH,0 ;reset AH
MOV AL,0 ;reset AL
PRSE1:
CMP B[SI]," " ;check for space
JE PRSE2X ;copy 1st operand to memory
INC SI ;next character
INC AH ;position count + 1
JMP PRSE1
PRSE2X:
MOV AL,AH ;copy position count
LEA DI,OPST1 + 2
PRSE2: ;copy first operand into memory
CMP AH,0
JE PRSE3
DEC SI
MOV BH,B[SI]
MOV B[DI],BH
DEC AH
DEC DI
JMP PRSE2
PRSE3: ;loop to find space again
CMP B[SI]," "
JE PRSE4
INC SI
JMP PRSE3
PRSE4: ;save operator to memory
INC SI
MOV BH,B[SI]
LEA DI,OPRTR
MOV B[DI],BH
MOV AH,0
MOV AL,0
INC SI ;move to expected pos of oprnd2
INC SI
PRSE5:
CMP B[SI]," " ;check for space
JE PRSE6X ;copy 2nd operand to memory
INC SI ;next character
INC AH ;position count + 1
JMP PRSE5
PRSE6X:
MOV AL,AH
LEA DI, OPST2 + 2
DEC SI
DEC AH
PRSE6:
CMP AH,0
JE PRSE7
DEC SI
MOV BH,B[SI]
MOV B[DI],BH
DEC AH
DEC DI
JMP PRSE6
PRSE7:
RET
;***************************************************************
;Subroutine CALC
;Performs integer calculations
CALC:
MOV BH,B[OPND1] ;load first operand into BH register
MOV BL,B[OPND2] ;load second operand into BL register
MOV DH,B[OPRTR] ;load operator byte into DH register
;find appropriate operation
CMP DH,"+" ;check for addition
JE ADDTN
CMP DH,"-" ;check for subtraction
JE SUBTN
CMP DH,"*" ;check for multiplication
JE MULTN
CMP DH,"/" ;check for division
JE DIVSN
JMP NOOPR ;if invalid operand
ADDTN: ;perform addition
MOV AH,0 ;clear upper half of destination
MOV AL,BH ;move 1st operand into AX
MOV BH,0 ;clear upper half of source
ADD AX,BX ;AX should now contain binary result
LEA SI,RESLT ;point SI at result buffer
CALL BA16
RET
SUBTN: ;perform subtraction
MOV AH,0 ;clear upper half of destination
MOV AL,BH ;move 1st operand into AX
MOV BH,0 ;clear upper half of source
SUB AX,BX ;AX should now contain binary result
LEA SI,RESLT ;point SI at result buffer
CALL BA16
RET
MULTN: ;perform multiplication
MOV AH,0 ;clear upper half of AX
MOV AL,BH ;move 1st operand into AL
MUL BL ;multiply it
LEA SI,RESLT ;point SI at result buffer
CALL BA16
RET
DIVSN: ;perform division
MOV AH,0 ;clear AH
MOV AL,BH ;load numerator into AH
DIV BL ;divide it
MOV CL,AH ;keep remainder in CL temporarily
MOV AH,0 ;clear upper half of AX
LEA SI,RESLT
CALL BA16 ;put quotient in result buffer
MOV AL,CL ;load remainder into AL
MOV AH,0 ;clear upper half of AX
LEA SI,RMNDR ;point SI at remainder buffer
CALL BA16
RET
NOOPR: ;tell the user they're being stupid
;TODO do this
;***************************************************************
;Subroutine LDZRO
;
;Eliminates leading 0s in 5 byte string
;
;ENTRY: SI points to string buffer location
;
;Exit: Where did the zeros go?
LDZRO:
CMP B[SI],"0"
JNE ZRTRN
MOV B[SI]," "
CMP B[SI+1],"0"
JNE ZRTRN
MOV B[SI+1]," "
CMP B[SI+2],"0"
JNE ZRTRN
MOV B[SI+2]," "
CMP B[SI+3],"0"
JNE ZRTRN
MOV B[SI+3]," "
RET
ZRTRN:
RET
INRST:
LEA SI,INBUF
MOV AL,20
INRS1:
DEC AL
CMP AL,0
JE INRS2
MOV B[SI],"_"
INC SI
JMP INRS1
INRS2:
RET
;***************************************************************
; SUBROUTINE BA16
;
; This subroutine converts a 16 bit binary value into 5 bytes
; of printable decimal ASCII.
;
; ENTRY: The 16 bit value is in register AX
; Regster SI points to the external 5 byte buffer
; EXIT: The external buffer contains the 5 characters
;
;****************************************************************
;
BA16: MOV DX, 0 ;clear upper half of dividend
MOV BX, 10000 ;set divisor
DIV BX ;create 10K character
MOV B[SI], AL ;save 10K count
MOV AX, DX ;get remainder
MOV DX, 0 ;clear upper half of dividend
MOV BX, 1000 ;set divisor
DIV BX ;create 1K character
MOV B[SI+1], AL ;save 1K count
MOV AX, DX ;get remainder
MOV DX,0 ;clear upper half of dividend
MOV BX, 100 ;set divisor
DIV BX ;create 100 character
MOV B[SI+2], AL ;save 100 count
MOV AX, DX ;get remainder
MOV BL, 10 ;set divisor
DIV BL ;create tens and units
MOV B[SI+3], AL ;save tens count
MOV B[SI+4], AH ;save units count
ADD B[SI], 30H ;convert binary digits to ASCII
ADD B[SI+1], 30H
ADD B[SI+2], 30H
ADD B[SI+3], 30H
ADD B[SI+4], 30H
MOV B[SI+5], EOT ;place end of message mark
MOV BX, 5
ADD SI, BX ;point to byte after conversion
RET
;*******************************************************************
; SUBROUTINE EXIT
EXIT:
MOV AX,4C00H
INT 21H
RET
;*******************************************************************
;Subroutine A2B8
;
;This subroutine converts up to 3 bytes of ASCII into 8 bit binary
;The input value must not exceed 255 - base 10
;No error checking is performed
;
;ENTRY: SI points to input buffer
;EXIT: AL holds binary value
;
A2B8:
PUSH SI ;save SI on entry
LEA DI, MULT ;point to placeholder values
SUB B[SI], 30H ;remove ASCII bias from numbers
SUB B[SI + 1], 30H
SUB B[SI + 2], 30H
MOV CX, 3 ;initialize loop counter
MOV BL, 0 ;initialize sum register
AB1: MOV AL, [SI] ;get first byte
MOV AH, 0 ;clear upper byte of AX
MUL B[DI] ;multiply by placeholder
ADD BL, AL ;save value
INC DI ;point to next place holder
INC SI ;point to next byte
LOOP AB1
MOV AL, BL ;place sum into output register
POP SI ;restore SI
RET
MULT DB 100, 10, 1
;*******************
;*******************
;print values subroutine for debug purposes
VALUS:
;next line
MOV AH,02H
MOV DL,LF
INT 21H
MOV AH,02H
MOV DL,CR
INT 21H
;print 1st operand
MOV AH,02H
MOV DL,B[OPST1]
INT 21H
MOV AH,02H
MOV DL,B[OPST1 + 1]
INT 21H
MOV AH,02H
MOV DL,B[OPST1 + 2]
INT 21H
;next line
MOV AH,02H
MOV DL,LF
INT 21H
MOV AH,02H
MOV DL,CR
INT 21H
;print operator
MOV AH,02H
MOV DL,B[OPRTR]
INT 21H
;next line
MOV AH,02H
MOV DL,LF
INT 21H
MOV AH,02H
MOV DL,CR
INT 21H
;print 2nd operand
MOV AH,02H
MOV DL,B[OPST2]
INT 21H
MOV AH,02H
MOV DL,B[OPST2 + 1]
INT 21H
MOV AH,02H
MOV DL,B[OPST2 + 2]
INT 21H
RET