基于emu8086的排序、数值转换及成绩汇总

基于emu8086的排序、数值转换及成绩汇总


一、目标

  1. 排序:对输入的多个数字进行排序。
    要求:
    (1) 所有数字从键盘输入
    (2) 数字中至少包含一个大于10的数字
    (3) 排好序的数字以十进制形式在屏幕显示输出

  2. 数制转换:将输入的一个数据以不同进制形式输出
    要求:
    (1) 所有数字从键盘输入
    (2) 输入数据为任意一个小于十万的十进制数据
    (3) 将所输入数据以十六进制在屏幕显示输出(即十进制转十六进制)

  3. 成绩汇总:对输入的一些成绩进行分类汇总。
    要求:
    (1) 所有数字由键盘输入
    (2) 输入的成绩个数为任意个(小于100)
    (3) 对成绩进行归类并输出显示在屏幕
    ·显示最高成绩、最低成绩、平均成绩
    ·显示90-100分人数,80-89分人数,70-79分人数,60-69分人数,低于60分人数
    ·显示无效数字个数(非数字或大于100数字个数)

二、核心代码

1、排序

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
DATA SEGMENT   ;数据段
STRING1 DB 'Input the number: ','$'
STRING2 DB 'The order from min to max:','$'
STRING DW 100 DUP(0) ;分配存放空间
DATA ENDS

STACK SEGMENT ;堆栈段
DW 64 DUP(0)
STACK ENDS

CODE SEGMENT ;代码段
ASSUME CS:CODE,DS:DATA,ES:DATA,SS:STACK
START:
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV AX,STACK
MOV SS,AX

MOV DX,OFFSET STRING1 ;显示提示输入
MOV AH,09H
INT 21H

XOR BX,BX ;寄存器清零
XOR CX,CX
XOR SI,SI
XOR DI,DI

INPUT:
MOV AH,01 ;1号中断 单个字符输入 带回显
INT 21H
CMP AL,0DH ;是否为回车
JZ DONE ;是就跳到DONE 说明字符串输入结束
CMP AL,20H ;是否为空格
JZ SAVE ;是就跳到SAVE
SUB AL,30H ;ASCII码变为十进制
MOV CL,4
SHL BX,CL ;之前输入的存进高位,变为BCD码
ADD BL,AL
JMP INPUT

SAVE:
MOV STRING[SI],BX ;保存到SCORE中
ADD SI,2
INC DI
XOR BX,BX
JMP INPUT

DONE:
MOV STRING[SI],BX ;保存最后一个数据到STRING中
INC DI
MOV DL,0AH ;换行
MOV AH,02H ;
INT 21H
MOV CX,DI ;外层循环次数
DEC CX
XOR BX,BX


COMP1:
MOV SI,2 ;指向下一个数
MOV DX,CX

COMP2:
MOV AX,STRING[BX]
CMP AX,STRING[BX+SI] ;比较前后两个数
JC COMP3 ;小于就跳到COMP3
XCHG AX,STRING[BX+SI] ;交换位置
MOV STRING[BX],AX

COMP3:
ADD SI,2 ;指向下一个数
DEC DX ;内层循环次数
JNZ COMP2
ADD BX,2 ;指向下一个数
LOOP COMP1

MOV DX,OFFSET STRING2
MOV AH,09H
INT 21H
XOR SI,SI ;把SI清零

OUTPUT:
MOV BX,STRING[SI]
MOV DL,BH ;输出千位
MOV CL,4
SHR DL,CL
ADD DL,30H
MOV AH,02H
INT 21H

MOV DL,BH ;输出百位数
AND DL,0FH
ADD DL,30H
MOV AH,02H
INT 21H

MOV DL,BL ;输出十位数
MOV CL,4
SHR DL,CL
ADD DL,30H
MOV AH,02H
INT 21H

MOV DL,BL ;输出个位数
AND DL,0FH
ADD DL,30H
MOV AH,02H
INT 21H

MOV DL,20H ;输出空格
MOV AH,02H
INT 21H
ADD SI,2
DEC DI

JNZ OUTPUT

MOV AH,4CH ;返回DOS 终止进程
INT 21H

CODE ENDS
END START

2、数制转换

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
STACK     SEGMENT STACK 'STACK'
DW 100H DUP(0)
TOP LABEL WORD
STACK ENDS

DATA SEGMENT
KEYBUFFER DB 100 ;开辟键盘缓冲区
DB 0
DB 100 DUP(0)
VAR1 DD 100 DUP(0)
STRING1 DB 'INPUT DECIMAL DATA: $'
DATA ENDS

CODE SEGMENT
ASSUME CS:DODE,DS:DATA,ES:DATA,SS:STACK
START:
MOV AX,DATA ;初始段地址
MOV DS,AX
MOV ES,AX
MOV AX,STACK
MOV SS,AX
LEA SP,TOP

LEA DX,STRING1 ;显示'输入提示字符串'
MOV AH,09H
INT 21H
MOV AH,0AH ;输入十进制数据到缓冲区
LEA DX,KEYBUFFER
INT 21H
LEA SI,KEYBUFFER+1 ;将缓冲区地址赋给SI

CALL TRANS10TO16 ;调用进制转换子函数
CALL DISPCR ;光标回车换行子程序
PUSH AX
PUSH DX
JC TRANSF_CF ;有进位则DX为1

POP DX
POP AX
CALL DISPAX ;以16进制显示结果

MOV AH,4CH
MOV AL,0
INT 21H

TRANSF_CF:
MOV AL,31H
MOV AH,02
MOV DL,AL
INT 21H

DISPAL PROC NEAR
PUSH AX
PUSH CX
PUSH DX
PUSH AX

MOV CL,4 ;处理高位16进制数
SHR AL,CL
CALL CHANG ;显示
MOV AH,02 ;
MOV DL,AL
INT 21H
POP AX
AND AL,0FH ;处理低位16进制数
CALL CHANG
MOV AH,02
MOV DL,AL
INT 21H

POP CX
POP DX
POP AX
RET
DISPAL ENDP


CHANG PROC NEAR
CMP AL,10
JNGE CHANG1 ;小于10
ADD AL,7
CHANG1:
ADD AL,30H
RET
CHANG ENDP

DISPAX PROC NEAR
XCHG AL,AH ;DISPAL子程序中先显示高位16位,再显示低位16
CALL DISPAL
XCHG AH,AL
CALL DISPAL
RET
DISPAX ENDP

DISPCR PROC NEAR
PUSH AX
PUSH DX
MOV AH,2
MOV DL,0AH ;换行
INT 21H
MOV AH,2
MOV DL,0DH ;回车
INT 21H
POP DX
POP AX
RET
DISPCR ENDP

TRANS10TO16 PROC NEAR
PUSH CX ;保存现场
PUSH DX
PUSH SI
XOR AX,AX
XOR CX,CX
MOV CL,[SI] ;CL中存放位数
INC SI ;AX存放每位的数字或者转换后的结果
MOV AL,[SI]
INC SI
SUB AL,30H ;由ASCIII码转成真数

DEC CX
JCXZ TRANSF_OK ;循环次数为零(每位都取出)后,转向TRANSF_OK
MOV BX,10

TRANSF:
MUL BX
MOV DL,[SI]
INC SI
SUB DL,30H
ADD AX,DX
LOOP TRANSF

TRANSF_OK: ;恢复现场,返回调用函数
POP SI
POP DX
POP CX
RET

TRANS10TO16 ENDP

CODE ENDS
END START

3、成绩汇总

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
DATA     SEGMENT
STRING1 DB 'Please Input Score:',0dh,0ah,24h
STRING2 DB 'THE MAX SCORE IS: ',0dh,0ah,24h
STRING3 DB 'THE MIN SCORE IS: ',0dh,0ah,24h
STRING4 DB 'THE AVERAGE SCORE IS:',0dh,0ah,24h
STR1 DB 'THE NUM OF 0-59:',0dh,0ah,24h
STR2 DB 'THE NUM OF 60-69: ',0dh,0ah,24h
STR3 DB 'THE NUM OF 70-79: ',0dh,0ah,24h
STR4 DB 'THE NUM OF 80-89: ',0dh,0ah,24h
STR5 DB 'THE NUM OF 90-100: ',0dh,0ah,24h
STR6 DB 'THE WRONG NUM:',0dh,0ah,24h
SCORE DW 60 DUP(0)
DECIMAL DB 5 DUP(0)
S5 DW 0
S6 DW 0
S7 DW 0
S8 DW 0
S9 DW 0
S10 DW 0
DATA ENDS

STACK SEGMENT
DW 128 DUP(0)
TOP LABEL WORD
STACK ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK
START:
MOV AX,DATA
MOV DS,AX
MOV AX,STACK
MOV SS,AX
LEA SP,TOP
MOV DX,OFFSET STRING1
MOV AH,09H
INT 21H

XOR BX,BX
XOR CX,CX
XOR SI,SI
XOR DI,DI

;排序
INPUT: MOV AH,1 ;输入一个字符
INT 21H
CMP AL,0DH
JZ OVER ;是回车则OVER
CMP AL,20H
JZ SAVE ;是空格则SAVE

SUB AL,30H
MOV CL,4
SHL BX,CL
ADD BL,AL ;把AL存入BL
CMP BX,100H
JG ERR_COUNT ;大于100则ERR

JMP INPUT

ERR_COUNT:
INC S10
MOV BX,0
JMP INPUT

SAVE:
MOV SCORE[SI],BX ;保存到SCORE中
ADD SI,2
INC DI
XOR BX,BX
JMP INPUT


OVER: MOV SCORE[SI],BX ;保存最后一个数据,并存放到SCORE中
INC DI
MOV DL,0AH
MOV AH,02H
INT 21H ;换行
MOV CX,DI ;外循环
DEC CX
PUSH DI ;输入个数入栈 三次?
PUSH DI
PUSH DI
XOR BX,BX

COMP1: MOV SI,2 ;指向下一个数
MOV DX,CX

COMP2: MOV AX,SCORE[BX]
CMP AX,SCORE[BX+SI] ;比较前后两个数
JNC COMP3 ;小于就跳到COMP3
XCHG AX,SCORE[BX+SI] ;交换位置
MOV SCORE[BX],AX

COMP3: ADD SI,2 ;指向下一个数
DEC DX
JNZ COMP2
ADD BX,2 ;指向下一个数
LOOP COMP1

XOR SI,SI ;把SI清零

;输出最高成绩
OUT_PUT:
LEA DX,STRING2 ;输出有效最大值
MOV AH,9
INT 21H

MOV BX,SCORE
;输出百位数
MOV DL,BH
AND DL,0FH
ADD DL,30H
MOV AH,02H
INT 21H

MOV DL,BL ;输出十位数
MOV CL,4
SHR DL,CL
ADD DL,30H
MOV AH,02H
INT 21H

MOV DL,BL ;输出个位数
AND DL,0FH
ADD DL,30H
MOV AH,02H
INT 21H

;输出最低成绩
CALL DISPCR
LEA DX,STRING3 ;输出最小有效值
MOV AH,9
INT 21H
POP DI
DEC DI
SUB DI,S10
SHL DI,1 ;每个成绩为一个字,而DI相当于存放的几个字节

MOV BX,SCORE[DI] ;输出百位数 OFFSET SCORE+(DI) DI左移一位相当于乘二,由一个字节变为一个字
MOV DL,BH
AND DL,0FH
ADD DL,30H
MOV AH,02H
INT 21H

MOV DL,BL ;输出十位数
MOV CL,4
SHR DL,CL
ADD DL,30H
MOV AH,02H
INT 21H

MOV DL,BL ;输出个位数
AND DL,0FH
ADD DL,30H
MOV AH,02H
INT 21H

;输出平均成绩
CALL DISPCR
LEA DX,STRING4
MOV AH,9
INT 21H

POP DI
LEA AX,SCORE
PUSH AX
CALL COMPUTMEAN
POP AX
CALL DISPAX ;显示Ax内容



;显示各分数段成绩个数
POP DI
MOV CX,DI
SUB CX,S10 ;设置计数器为DI
LEA BX,SCORE

COMPARE: MOV AX,[BX]
CMP AX,60H ;与60比较
JL FIVE ;小于就跳到FIVE
CMP AX,70H ;与70比较
JL SIX ;小于就跳到SIX
CMP AX,80H ;与80比较
JL SEVEN ;小于就跳到SEVEN
CMP AX,90H ;与90比较
JL EIGHT ;小于就跳到EIGHT
CMP AX,100H ;与100比较
JLE NINE ;不为0就是90100

JMP NEWDATA ;跳到NEWDATA

FIVE: INC S5 ;小于60时【S5+1
JMP NEWDATA ;跳到NEWDATA
SIX: INC S6 ;大于等于60小于70时【S6+1
JMP NEWDATA ;跳到NEWDATA
SEVEN: INC S7 ;大于等于70小于80时【S7+1
JMP NEWDATA ;跳到NEWDATA
EIGHT: INC S8 ;大于等于80小于90时【S8+1
JMP NEWDATA ;跳到NEWDATA
NINE: INC S9 ;大于等于90小于等于100时【S9+1

NEWDATA: ADD BX,2 ;取下个数
LOOP COMPARE ;循环COMPARE

CALL DISPCR
LEA DX,STR1
MOV AH,09H
INT 21H
MOV AX,S5
CALL DISPAXD

CALL DISPCR
LEA DX,STR2
MOV AH,09H
INT 21H
MOV AX,S6
CALL DISPAXD

CALL DISPCR
LEA DX,STR3
MOV AH,09H
INT 21H
MOV AX,S7
CALL DISPAXD

CALL DISPCR
LEA DX,STR4
MOV AH,09H
INT 21H
MOV AX,S8
CALL DISPAXD

CALL DISPCR
LEA DX,STR5
MOV AH,09H
INT 21H
MOV AX,S9
CALL DISPAXD

CALL DISPCR
LEA DX,STR6
MOV AH,09H
INT 21H
MOV AX,S10
CALL DISPAXD

MOV AH,4CH ;返回DOS
INT 21H

; 将16位二进制数(AX)转化成十进制数并显示在频幕上
DISPAXD PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
LEA DI,DECIMAL ;在数据段定义DECIMAL(5字节)
CALL TRANS16TO10
MOV CX,5
LEA DI,DECIMAL+4
MOV AH,2
DISPAXD2:
MOV DL,[DI]
ADD DL,30H
DEC DI
INT 21H
LOOP DISPAXD2
POP DI
POP DX
POP CX
POP BX
POP AX
RET
DISPAXD ENDP

;将16位二进制数转化成十进制数并保存在指定缓冲区中
TRANS16TO10 PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
MOV BX,10
MOV CX,5
TRANS1:
XOR DX,DX
DIV BX ;在此子函数一开始 AX中为BX的内容(score里的数据)
MOV [DI],DL
INC DI
LOOP TRANS1
POP DI
POP DX
POP CX
POP BX
POP AX
RET
TRANS16TO10 ENDP
;显示AL,AX寄存器内容
DISPAL PROC NEAR
PUSH AX
PUSH CX
PUSH DX
PUSH AX
MOV CL,4 ;处理高位十六进制数
SHR AL,CL
CALL CHANG ;十六进制数变换成ASCII码
MOV AH,02
MOV DL,AL
INT 21H
POP AX
AND AL,0FH ;处理低位十六进制数
CALL CHANG
MOV AH,02
MOV DL,AL
INT 21H
POP DX
POP CX
POP AX
RET
DISPAL ENDP

CHANG PROC NEAR ;数码转换
CMP AL,10
JNGE CHANG1
ADD AL,7
CHANG1:
ADD AL,30H
RET
CHANG ENDP

DISPAX PROC NEAR
XCHG AL,AH
CALL DISPAL
XCHG AH,AL
CALL DISPAL
RET
DISPAX ENDP

DISPCR PROC NEAR
PUSH AX
PUSH DX
MOV AH,2
MOV DL,0AH
INT 21H
MOV AH,2
MOV DL,0DH
INT 21H
POP DX
POP AX
RET
DISPCR ENDP
;计算平均值
COMPUTMEAN PROC NEAR
PUSH BP
MOV BP,SP ;BP SP的段地址均为SS
PUSH SI
PUSH DI
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV SI,[BP+4] ;?数据区首地址 之前AX(score首地址)入栈,所以SP现在指向AX最高端地址
XOR DX,DX
XOR BX,BX

SUB DI,S10 ;循环条件
MOV CX,DI
XOR DI,DI
PUSH CX ;留作除法
CPTM1:
MOV AX,[SI]
ADD SI,2
ADD BX,AX ;以bcd码的方式存储的,因此做daa修正
DAA
ADC DI,DX ;保存修正时的进位
DAA
LOOP CPTM1
MOV DX,DI ;用DX与AX保存是因IDIV的字运算,隐含被除数在DX AX中,结果保存在AX中
MOV AX,BX
POP CX ;有符号数除法
IDIV CX

MOV [BP+4],AX
POP DX
POP CX
POP BX
POP AX
POP DI
POP SI
POP BP
RET
COMPUTMEAN ENDP
CODE ENDS
END START