王爽汇编第三版实验10.3 浅析

同实验10.2,不上题目了。

题目大概就是说,将保存在数据段的字型的数值,以10进制的方式显示在屏幕上。这里涉及到两点,一是打印到屏幕,即打印到内存空间B8000H~BFFFFH之间,其中每个字符占一个字,高位存放属性,低位存放字符,这段32KB的空间共可以显示25*80个字符,也就是每行80*2=160个字节。

二就是将存放在内存当中的二进制数值(以十六进制的方式显示),转换成10进制。因为显存只认识ASCII码,又因为数据在内存中是以十六进制显示的,所以我们将在数据段中的数值变为ASCII码中的十六进制。

0~9在ASCII码中的范围是30H~39H,我们要将数字中的每一位都转换成这种形式。

怎么取每一位,用书上讲的一直除10,除到商为0时,就结束。这种方法得到的每一位的顺序刚好是相反的,即12366取每一位的顺序是66321,这样我们可以用栈来解决,每取到一位,加上30H,然后进栈,最后我们要打印的时候依次取出来就行了。

到了这里还有一些问题,比如:你取位的时候可以通过判断商是否为0来结束,那么你打印的时候又怎么判断有多少位?我一开始想到的是在循环里面计数,可是难以实现,因为寄存器不够用,而我又不想用。当然你可以在栈顶(SS:[0])中来计数,每打印完一个数,就清零,这种方法我还没有去实现,还有另外一种方法就是,根据SP寄存器的相对偏移来确定到底有几位,我用的就是这种方法。

然后还有,如果数据段的数不止一个数,那么怎么判断后面是否还有数?这个我们可以根据0来判断,我们可以在数据段的最后加一个0,然后每次读其中的数的时候,把这个数的值给CX,用JCXZ来结束程序。

下面放代码

DATAS SEGMENT
    dw 123,12366,1,8,3,38,9;此处输入数据段代码  
DATAS ENDS

STACKS SEGMENT
    dw 200 dup(0);此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
    MOV AX,DATAS
    MOV DS,AX
    
    MOV AX,0B800H
    MOV ES,AX
    MOV DI,0
    MOV SI,0
    
    MOV AX,STACKS
    MOV SS,AX
 	MOV SP,801
 	
 	MOV DH,8   ;行
    MOV DL,3	;列
    MOV CL,2	;颜色
	sub dl,1
	MOV AL,160
	MUL DH
	MOV DI,AX	;计算行偏移
	
	MOV AX,2
	MUL DL
	ADD DI,AX	;行+列偏移 保存在DI
 	
	
    CALL dtoc
    
    
    MOV AX,4C00H
    INT 21H
 
show_str:
	 MOV CL,2	;颜色
	push cx   ;颜色进栈
	
	MOV CX,801
	SUB CX,SP
	MOV AX,CX
	MOV Bl,2
	DIV Bl
	SUB AX,2
	MOV CX,AX
	;计算CX的值
	p:
		POP BX	;颜色出栈
		POP DX
		MOV ES:[DI],DL
		MOV ES:[DI+1],bl
		add DI,2
		PUSH BX
	LOOP p
	
	POP BX
	
	add SI,2
	jmp short dtoc

dtoc:
	MOV AX,DS:[SI]
	MOV CX,AX
	JCXZ return
	s:
		MOV CL,AL
		MOV CH,0
		JCXZ ok		;商为0时打印
		MOV DX,0
		MOV BX,10
		DIV BX		;商在AX 余数在DX
		MOV BX, 30H
		ADD DX,BX
		PUSH DX
		jmp short s
	ok:
		jmp  short show_str
	return:
		ret
	
			
CODES ENDS
    END START

做题目的时候差点被坑,因为这里12366/10,也就是 16位/8位,商保存在AL,余数保存在AH,然后就会发生溢出错误,因为AL保存不了这么大的值,这里只能用32位/16位来解决。在打印的计算CX那里,用SP最开始的值-当前的SP的值,再除2,因栈是字为单位的,一个字等于两个字节,然后在-2,为什么要-2呢?

因为在CODES段中 CALL了 dtoc ,这时候CPU会把CALL的下一个地址进栈,然后在show_str中把颜色进栈了,所以我们要减去2,就能得到正确的CX结果了。还有在p段结束后,要记得POP BX,因为最后一个循环PUSH了一个值,如果不将其出栈,那么CALL dtoc的下一条指令就不会执行,程序就不能正常结束。

还有一点 就是关于列的,为什么要-1 。因为第三列(现实生活的计数,从1开始)就是里面的第二列,00 01 02 03 04 05,我们要定位到04这个内存单元,我们可以(3-1)*2,等于4。

以后想到再补充了,欢迎大家一起学习交流。

猜你喜欢

转载自blog.csdn.net/freedomosfortjm/article/details/75332224