-
Notifications
You must be signed in to change notification settings - Fork 0
/
sorthem.asm
389 lines (251 loc) · 8.57 KB
/
sorthem.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
%include "asm_io.inc"
SEGMENT .data
; Strings
error1: db "Incorrect number of command line arguments!",0
error2: db "Number of disks out of range!",0
usage: db "Usage: n",10,"n: Number of disks, 2 <= n <= 9",0
initial db "Initial configuration:",0
final db "Final configuration:",0
peg_base: db "XXXXXXXXXXXXXXXXXXXXX",0
; Intialize an array for the peg to zero
peg_arr: dd 0,0,0,0,0,0,0,0,0
SEGMENT .bss
; Number of disks
num_disks: resd 1
SEGMENT .text
global asm_main
; Sort the disks recursively using a variation of insertion sort (I think that's what this algorithm is)
sorthem:
enter 0, 0
pusha
; Access the command line arguments
mov edx, [ebp + 8] ; get the pointer to the array
mov ebx, [ebp + 12] ; get the size of the array
cmp ebx, dword 1 ; if the array is of size one it is sorted
je SORTHEM_END ; Might as well skip checking if printing
; is needed because we already know that no
; Recursive call to sorthem with parameters (arraypointer + 4) and (sizeofarray - 1)
mov eax, ebx
sub eax, 1
push eax
mov eax, edx
add eax, 4
push eax
call sorthem
add esp, 8
; The top pegs are now sorted
; Iterate through the disks and swap the current disk until it is in the right spot
SWAPPING_LOOP:
mov eax, [edx + 4] ; The value of the next element in the array is now in eax
cmp [edx], eax
ja SORTHEM_PRINT ; If the next value is smaller, disk is in place, no need to do more swapping
; Swap this value and the next value using ecx as the intermediary variable
mov ecx, [edx]
mov [edx], eax
mov [edx + 4], ecx
; Decrement the counter (ebx) and move the array pointer to the next value
sub ebx, 1
add edx, 4
; If there are still possible swaps, keep going (otherwise fall through)
cmp ebx, dword 1
ja SWAPPING_LOOP
SORTHEM_PRINT:
; Check if no swaps were done. If this is the case, don't bother printing
cmp ebx, [ebp + 12] ; Check counter against original value. If same, no swaps were performed
je SORTHEM_END
; Call showp to see the current configuration
mov eax, [num_disks] ; Push the FULL array size
push eax
mov eax, peg_arr ; Push the FULL array pointer
push eax
call showp
add esp, 8
SORTHEM_END:
popa
leave
ret
; Subroutine to draw a disk
display_disk:
enter 0,0
pusha
; Get the size of the disk
mov ecx, [ebp + 8]
mov ebx, 10
sub ebx, ecx ; Set ebx to the number of spaces that need to be printed
; Print the spaces before the start of the disk
SPACE_PRINT_LOOP:
mov al, byte ' '
call print_char
sub ebx, 1 ; Decrement counter
cmp ebx, 0
jg SPACE_PRINT_LOOP
; Set up ebx as a counter
mov ebx, ecx
mov al, byte 'o' ; Put the character for the disk in al
LETTER_PRINT_LOOP_1:
call print_char
; Check if we need to keep going
sub ebx, 1
cmp ebx, 0
jg LETTER_PRINT_LOOP_1
; Print the pipe
mov al, byte '|'
call print_char
; Set up ebx as a counter and put the character for the disk in al
mov ebx, ecx
mov al, byte 'o'
; Print the rest of the disk
LETTER_PRINT_LOOP_2:
call print_char
; Check if we need to keep going
sub ebx, 1
cmp ebx, 0
jg LETTER_PRINT_LOOP_2
; Print a newline to make things look pretty
call print_nl
popa
leave
ret
; Print the current configuration of the disks
showp:
enter 0, 0
pusha
; Get the value of the parameters
mov ebx, dword [ebp + 8] ; Holds the address of the peg array
mov ecx, dword [ebp + 12] ; Holds the number of items on the peg
; Set up ebx to point at the last element instead of the first
mov eax, ecx
sub eax, 1
shl eax, 2 ; Multiply eax by 4 using bitshifts because multiplying
add ebx, eax ; by a constant is less efficient and harder to figure out
; print the configuration to the standard output using a loop
mov edx, 0 ; Use edx as a counter for the printing loop
PEGPRINTLooP:
mov eax, dword [ebx]
push eax
call display_disk ; Set up and call the function to print the disk
add esp, 4
inc edx ; increment the counter
sub ebx, dword 4 ; Move ebx to the next number, recalling
; that we are printing starting the end of the array
; Check if we are done printing or not
cmp edx, ecx
jb PEGPRINTLooP
; Print the base
mov eax, peg_base
call print_string
call print_nl
; Wait for the user to press a character
call read_char
; Return to the calling function
popa
leave
ret
; Entry point for c driver code
asm_main:
enter 0,0
pusha
; Get the number of command line args and store in register b
mov ebx, dword [ebp+8]
; Check number against 2, the expected number of command line arguments
cmp ebx, dword 2
je NUM_GOOD
; Print that the number of arguments was incorrect
mov eax, error1
call print_string
; Print a newline
call print_nl
; Print usage
mov eax, usage
call print_string
call print_nl
; Jump to error ending
jmp END_BAD
; If the correct number of arguments are input
NUM_GOOD:
; Move the address of the first string into reg b
mov ebx, [ebp+12]
mov ebx, [ebx + 4] ; Put pointer to first char of second string in ebx
mov cl, byte [ebx+1] ; Move the second character into cl reg
; Check if the second character is the null-terminator
cmp cl, byte 0
je INPUT_LENGTH_GOOD
; If the length of the input string is wrong
mov eax, error2
call print_string
call print_nl
mov eax, usage
call print_string
call print_nl
jmp END_BAD
; If the length of the input string is good
INPUT_LENGTH_GOOD:
mov cl, byte [ebx] ; Move the first character of the string into the al reg
cmp cl, byte '1'
jg LOWER_BOUNDS_GOOD
; Number is out of range; output error message, usage, and exit with error code
mov eax, error2
call print_string
call print_nl
mov eax, usage
call print_string
call print_nl
jmp END_BAD
; If lower bounds are good, then the upper bounds are good because 10 requires two characters
LOWER_BOUNDS_GOOD:
; This is where the error handling ends and the interesting part of
; the program begins
; Calculate the number and stow it away in the .bss segment
sub cl, '0' ; Convert the input into an unsigned number
mov edx, 0
add dl, cl ; Cleanup the number and put into edx for pushing
mov [num_disks], edx ; Stow
; Make the peg configuration using rconf
mov eax, peg_arr
push edx ; Push the number of items on the peg
push eax ; Push the pointer to the array for rconf
call rconf ; Call the randomization function and cleanup parameters
add esp, 8
; Print the initial configuration string
mov eax, initial
call print_string
call print_nl
call print_nl
; Call the function to print the configuration of the stack
mov edx, [num_disks]
mov eax, peg_arr
push edx
push eax
call showp
add esp, 8
; Call the function to sort the disks
mov edx, [num_disks]
mov eax, peg_arr
push edx
push eax
call sorthem
add esp, 8
; Print the final configuration string
mov eax, final
call print_string
call print_nl
call print_nl
; Call the function to print the configuration of the stack
mov edx, [num_disks]
mov eax, peg_arr
push edx
push eax
call showp
add esp, 8
END:
; Return values to registers, leave the stack frame, and return control to the c driver
popa
mov eax, 0 ; Don't forget that you are returning 0 for success
leave
ret
; Same as the first end, excepts puts 1 in eax to indicate an error
END_BAD:
popa
mov eax, 1
leave
ret