-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathproj1.final.asm
More file actions
365 lines (333 loc) · 11.6 KB
/
proj1.final.asm
File metadata and controls
365 lines (333 loc) · 11.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
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
##############################################################################
# Assignment 1
# Michael Leonhard
# CS 366 Prof. Ashfaq Khokhar
# TA: Mani Radhakrishnan
# 3 Oct 2005
# PC SPIM 7.2
##############################################################################
#
# This program tests users inputted integers to see if they fall within a user
# provided range. When the program starts, it prompts the user for a minimum
# and maximum value. Then it enters a loop where it prompts the user for a
# number and reports if the number falls inside the range. Let the inputted
# number be X. The program prints "In" when minimum <= X <= maximum, otherwise
# it prints "Out".
#
# * Psuedocode
#
# llim <-- LowerLimit
# ulim <-- UpperLimit
#
# print prompt for min
# min <-- 32bit signed integer from console
# print prompt for max
# max <-- 32bit signed integer from console
# if min = -2^31 and max = 2~31 - 1 then halt
# if min > max then print error and halt
#
# lterm <-- min - 1
# uterm <-- max + 1
# if min = -2^31 then lterm <-- uterm
# if max = 2^31 - 1 then uterm <-- lterm
#
# LOOP:
# print prompt for number
# num <-- 32bit signed integer from console
# if num = lterm then halt
# if num = uterm then halt
# if min <= num <= max then print "In"
# else print "Out"
#
# * Register Allocations and Variable Descriptions
# llim$s1 lower limit for unsigned int, -2^31
# ulim$s2 upper limit for usigned int, 2^31 - 1
# num$s3 number to test in loop, read from user
# lterm$s4 lower termination value (set to min$s6 - 1)
# uterm$s5 upper termination value (set to max$s7 + 1)
# min$s6 upper limit of range (inclusive)
# max$s7 lower limit of range (inclusive)
#
# * Testing
# Testing was done manually on the following (min,max) values. For each test,
# various values were tested and the result checked. The last tested value
# terminates the program.
#
# (min, max): tested values
# (0, 0): -2147483648, -2000000000, -5, 0, 5, 2000000000, 2147483647, 1
# (-1, 1): -2147483648, -2000000000, -5, 0, 5, 2000000000, 2147483647, -2
# (-2147483648, 1): -2147483648, -2000000000, -5, 0, 5, 2000000000, 2147483647, 2
# (-1, 2147483647): -2147483648, -2000000000, -5, 0, 5, 2000000000, 2147483647, -2
# (100, 200): -2147483648, -2000000000, -5, 0, 5, 100, 150, 200, 2000000000, 2147483647, 99
# (-200, -100): -2147483648, -2000000000, -200, -150, -100, -5, 0, 5, 2000000000, 2147483647, -99
# Tested error conditions:
# (1, 0) -> error
# (1, -1) -> error
# (2147483647, -2147483648) -> error
# (-2147483648, 2147483647) -> halt
#
#
# TODO: transform program to be easily programmatically testable, by changing it
# into several functions (using the stack to save registers)
# TODO: write a program to generate a subroutine to test 9^3 cases from the
# cartesian product of the set:
# {-2147483648, -2147483647, -2, -1, 0, 1, 2, 2147483646, 2147483647 }
#
# * Note on Termination Conditions
# The definition of the termination condition does not specify specific
# behavior for when either min or max is at its respective limit. Calculation
# of the associated terminal value would overflow the 32bit unsigned integer
# data type:
#
# When min = -2^31:
# lterm <-- min -1 = -2^31 - 1 = 2^31 overflowed
# When max = 2^31 - 1:
# uterm = max + 1 = 2^31 - 1 + 1 = 2^31 = -2^31 overflowed
#
# This program implements an algorithm to avoid the overflow. It tests for
# these cases and sets both termination condition values to the non-overflowing
# value. This means that the uncalculable termination condition is ignored:
#
# lterm <-- min - 1
# uterm <-- max + 1
# if min = -2^31 then lterm <-- uterm
# if max = 2^31 - 1 then uterm <-- lterm
#
# * Status
# Every part of the project specification is implemented.
# Testing indicates that the program functions properly.
#
#############################################################################
.data
.align 2
.jumptable: .word main, limitsok, minmaxok, skiplterm1, skiputerm1, skiplterm2, skiputerm2, loop, in, out, halt, compare, noskip1, noskip2, more, less, equal
UpperLimit: .word 2147483647
LowerLimit: .word -2147483648
# # strings for debugging messages
# MinString: .asciiz " Min:"
# MaxString: .asciiz " Max:"
# LTermString: .asciiz " LTerm:"
# UTermString: .asciiz " UTerm:"
# EnteredString: .asciiz" EnteredValue:"
# AString: .asciiz " A:"
# BString: .asciiz " B:"
# RetString: .asciiz " Ret:"
# strings for prompts and feedback to user
MinPrompt: .asciiz "Enter min: "
MaxPrompt: .asciiz "Enter max: "
NumPrompt: .asciiz "Enter number to test: "
MinGreaterMsg: .asciiz "Invalid input: min must be <= max\n"
InMsg: .asciiz "In\n"
OutMsg: .asciiz "Out\n"
.text
main:
# llim$s1 <-- LowerLimit
la $s0, LowerLimit # load address of constant
lw $s1, 0($s0) # load constant
# ulim$s2 <-- UpperLimit
la $s0, UpperLimit # load address of constant
lw $s2, 0($s0) # load constant
# print prompt for min
li $v0, 4 # operation = 4 (print string)
la $a0, MinPrompt # param = address of string
syscall # call O/S
# min$s6 <-- 32bit signed integer from console
li $v0, 5 # operation = 5 (read unsigned int from console)
syscall # call O/S
move $s6, $v0 # store result
# print prompt for max
li $v0, 4 # operation = 4 (print string)
la $a0, MaxPrompt # param = address of string
syscall # call O/S
# max$s7 <-- 32bit signed integer from console
li $v0, 5 # operation = 5 (read unsigned int from console)
syscall # call O/S
move $s7, $v0 # store result
# if min = -2^31 and max = 2~31 - 1 then halt
bne $s6, $s1, limitsok # if min$s6 != llim$s1 then limitsok
beq $s7, $s2, halt # if max$s7 = ulim$s2 then halt
limitsok:
# # DEBUG print MinString
# li $v0, 4 # operation = 4 (print string)
# la $a0, MinString # param = address of string
# syscall # call O/S
# # DEBUG print min$s6
# li $v0, 1 # operation = 1 (print signed 32bit integer)
# move $a0, $s6 # param = value
# syscall # call O/S
# # DEBUG print MaxString
# li $v0, 4 # operation = 4 (print string)
# la $a0, MaxString # param = address of string
# syscall # call O/S
# # DEBUG print max$s7
# li $v0, 1 # operation = 1 (print signed 32bit integer)
# move $a0, $s7 # param = value
# syscall # call O/S
# if min > max then print error and halt
#
# is performed as
#
# ret <-- compare(min, max)
# if ret<=0 then minmaxok
# else print error and halt
# ret <-- compare(min, max): (A<B -> -1),(A=B -> 0),(A>B -> 1)
move $a0, $s6 # A$a0 <-- min$s6
move $a1, $s7 # B$a1 <-- max$s7
jal compare # call subroutine, result is ret$v0
# if ret<=0 then minmaxok
blez $v0, minmaxok # if ret$v0 <= 0 then goto minmaxok
# else print error and halt
li $v0, 4 # operation = 4 (print string)
la $a0, MinGreaterMsg # param = address of string
syscall # call O/S
j halt # halt
minmaxok:
# lterm <-- min - 1
# uterm <-- max + 1
# if min = -2^31 then lterm <-- uterm
# if max = 2^31 - 1 then uterm <-- lterm
#
# to avoid overflow, this is is implemented as
#
# if min != -2^31 then lterm <-- min - 1
# if max != 2^31 - 1 then uterm <-- max + 1
# if min = -2^31 then lterm <-- uterm
# if max = 2^31 - 1 then uterm <-- lterm
# if min != -2^31 then lterm <-- min - 1
beq $s6, $s1, skiplterm1 # if min$s6 = llim$s1 skiplterm1
addi $s4, $s6, -1 # lterm$s4 <-- min$s6 - 1
skiplterm1:
# if max != 2^31 - 1 then uterm <-- max + 1
beq $s7, $s2, skiputerm1 # if max$s7 = ulim$s2 skiputerm1
addi $s5, $s7, 1 # uterm$s5 <-- max$s7 + 1
skiputerm1:
# if min = -2^31 then lterm <-- uterm
bne $s6, $s1, skiplterm2 # if min$s6 != llim$s1 skiplterm2
move $s4, $s5 # lterm$s4 <-- uterm$s5
skiplterm2:
# if max = 2^31 - 1 then uterm <-- lterm
bne $s7, $s2, skiputerm2 # if max$s7 != ulim$s2 skiputerm2
move $s5, $s4 # uterm$s5 <-- lterm$s4
skiputerm2:
# $s1 and $s2 are free from here down (in main, not subroutines)
# # DEBUG print LTermString
# li $v0, 4 # operation = 4 (print string)
# la $a0, LTermString # param = address of string
# syscall # call O/S
# # DEBUG print lterm$s4
# li $v0, 1 # operation = 1 (print signed 32bit integer)
# move $a0, $s4 # param = value
# syscall # call O/S
#
# # DEBUG print UTermString
# li $v0, 4 # operation = 4 (print string)
# la $a0, UTermString # param = address of string
# syscall # call O/S
# # DEBUG print uterm$s5
# li $v0, 1 # operation = 1 (print signed 32bit integer)
# move $a0, $s5 # param = value
# syscall # call O/S
loop:
# print NumPrompt
li $v0, 4 # operation = 4 (print string)
la $a0, NumPrompt # param = address of string
syscall # call O/S
# num$s3 <-- 32bit signed integer from console
li $v0, 5 # operation = 5 (read unsigned int from console)
syscall # call O/S
move $s3, $v0 # store result
# # DEBUG print EnteredString
# li $v0, 4 # operation = 4 (print string)
# la $a0, EnteredString # param = address of string
# syscall # call O/S
# # DEBUG print num$s3
# li $v0, 1 # operation = 1 (print signed 32bit integer)
# move $a0, $s3 # param = value
# syscall # call O/S
# if num = lterm then halt
beq $s3, $s4, halt # if num$s3 = lterm$s4 halt
# if num = uterm then halt
beq $s3, $s5, halt # if num$s3 = uterm$s5 halt
# if min <= num <= max then print "In"
# else print "Out"
#
# is performed as
#
# ret <-- compare(num, min)
# if ret<0 then out
# ret <-- compare(max, num)
# if ret<0 then out
# else in
# ret <-- compare(num, min): (A<B -> -1),(A=B -> 0),(A>B -> 1)
move $a0, $s3 # A$a0 <-- num$s3
move $a1, $s6 # B$a1 <-- min$s6
jal compare # call subroutine, result is ret$v0
# if ret<0 then out
bltz $v0, out # if ret$v0 < 0 then goto out
# ret <-- compare(max, num): (A<B -> -1),(A=B -> 0),(A>B -> 1)
move $a0, $s7 # A$a0 <-- max$s7
move $a1, $s3 # B$a1 <-- num$s3
jal compare # call subroutine, result is ret$v0
# if ret<0 then out
bltz $v0, out # if ret$v0 < 0 then goto out
# else in
in:
# print InMsg and loop
li $v0, 4 # operation = 4 (print string)
la $a0, InMsg # param = address of string
syscall # call O/S
j loop # goto loop
out:
# print OutMsg and loop
li $v0, 4 # operation = 4 (print string)
la $a0, OutMsg # param = address of string
syscall # call O/S
j loop # goto loop
halt:
# exit program
li $v0, 10
syscall
compare:
# $a0 = A
# $a1 = B
# $ra = return address
# $v0 = result = -1 if A<B, 0 if A=B, and 1 if A>B
# Method compares A and B, taking care to avoid arithmetic overflow
# Returns value in $v0 to indicate numerical relationship of A and B.
#
# This method evaluates A<B as A-B<0. This is performed in two steps: a
# subtraction and a test. The intermediate subtraction result, X, will
# overflow if X<-2^31 or X>2^31 -1. This can happen in two situations:
# A < 0 and 0 <= B has the potential for A-B<-2^31
# B < 0 and 0 <= A has the potential for A-B>2^31 -1
# These two cases reduce to A<B and B<A, respectively. Thus we can
# conveniently avoid overflow by testing for these cases before subtracting.
#
# if A=B then equal
# if A<0 and if B>=0 then less
# if A>=0 and if B<0 then more
# else if A-B<0 then less
# else more
# if A=B then equal
beq $a0, $a1, equal # if A$a0 = B$a1 then goto equal
# if A<0 and if B>=0 then less
bltz $a1, noskip1 # if B$a1 < 0 then goto noskip1
bltz $a0, less # if A$a0 < 0 then goto less
noskip1:
# if A>=0 and if B<0 then more
bltz $a0, noskip2 # if A$a0 < 0 then goto noskip2
bltz $a1, more # if B$a1 < 0 then goto more
noskip2:
# else if A-B<0 then less
sub $s0, $a0, $a1 # A$a0 - B$a1
bltz $s0, less # < 0 then goto less
# else more
more:
li $v0, 1 # return value is 1
jr $ra # return
less:
li $v0, -1 # return value is -1
jr $ra # return
equal:
li $v0, 0 # return value is 0
jr $ra # return