这段代码应将两个矩阵相乘以保持对应元素的符号
N EQU 3
M EQU 4
P EQU 2
.MODEL small
.STACK
.DATA
matA DB 4,-3,5,1,3,-5,0,11,-5,12,4,-5
matB DB -2,3,5,-1,4,3,9,-7
matC DW N*P DUP(?)
.CODE
.STARTUP
XOR AX,AX
XOR BX,BX
XOR CX,CX
XOR DX,DX
XOR SI,SI
XOR DI,DI
XOR BP,BP
MOV CX,N
decN:
PUSH CX
PUSH BX
MOV CX,P
decP:
PUSH CX
PUSH BP
MOV CX,M
MOV DI,0
decM:
PUSH CX
XOR AH,AH
MOV AL,matA[BX][DI]
PUSH BX
MOV BX,BP
MOV DL,matB[DI][BX]
POP BX
IMUL DL
MOV SI,BP
ADD matC[BX][SI],AX
INC DI
POP CX
LOOP decM
INC BP
POP CX
LOOP decP
INC BX
POP CX
LOOP decN
.EXIT
END
它不会终止,因为在第一个周期之后,当CX的值为0时,它会递减,因此它将FFFF压入堆栈,这会产生混乱。第二个问题是,在第一个循环之后,它无法从矩阵中选择正确的值。在decM:
下,由于仿真器计算出错误的偏移,我不得不将BP值移到BX中。
答案 0 :(得分:1)
matB[DI][BX]
不是2D索引,而只是matB[DI + BX]
。我不知道为什么emu8086支持这种令人困惑的语法,但是我不建议这样做。
8086机器码仅在寻址模式下支持简单加法,因此您需要add DI, N
之类的东西来跨越列向量。
在
decM
下:我必须将BP值移至BX,因为仿真器计算出的偏移量错误。
这很奇怪。起初,我想知道您的偏移量是否正确,但段基数是否错误(因为BP表示SS,而BX表示DS),但是.model small
gives you DS=SS。
但是我认为您需要自己初始化DS。如果我理解正确,则DOS .exe
的开头为DS base = PSP的开头。 Why doesn't MS-DOS initialize the DS and ES registers?。
因此,您可能具有正确的偏移量,但段基数错误,从而导致线性地址错误。如果BP
有效,那么在seg:off
寻址模式下错的不是偏移量。
修复此问题后,您应该能够使用调试器调试代码。分段可能会造成混淆,但是其余的分段应该很容易通过单步调试,并在手册中查找任何令人惊讶的说明。
[BP+BX]
不是有效的寻址模式,因此,是的,在MOV SI,BP
之前确实需要ADD matC[BX][SI],AX
。或add bx,bp
或其他可以破坏寄存器的东西。
您可能只需使用inc
或add reg,N
/ sub reg,P-1
或其他任何方法递增3个指针(目标,列源和行源)尝试将i
,j
和k
索引保留在寄存器中,并在每次2D访问之前对其进行缩放。
不均衡的推送/弹出
您的内部循环有2次推送和2次弹出。但是您的外部2个循环(decN
和decP
)每个都有2个推入和1个弹出。这似乎注定要失败,并且会用更大的N溢出堆栈。
我还没有尝试确切地弄清楚应该将哪个值发送到哪里,并且如果您要尝试始终将一个值弹出到它来自的寄存器中,或者利用保存/恢复作为将其弹出到其他寄存器的机会。您的代码中没有注释...
使用所有寄存器代替内存很好,但是 需要使用一些内存。如果将BP用作帧指针,则可能会花费更短的时间(并且代码效率更高),因此可以随机访问堆栈。限制自己进行推送/弹出以进行保存/还原意味着您必须在内部循环中保存/恢复,而不是仅在内存中保留一些外部循环的东西。
您可以在内存中保留一个循环计数器,例如dec byte [BP-2]
/ jnz decP
,而不是保存/恢复CX以将其用作所有3个循环的循环计数器。
或者在寄存器中使用指针,您可以检查它们,而不用将单独的寄存器或内存位置用作循环计数器。像
top_of_loop:
...
; bottom of a loop
cmp DI, OFFSET matC + N*P * 2
jb top_of_loop
; fall through when DI has
; or OFFSET matC + SIZEOF matC, or put a label at the end of matC
然后,您可以将CX用作临时文件(例如使用add cx, ax
来累积行/列点乘积,该乘积将成为结果矩阵的元素),或者如果您想支持运行时,则可以保留循环绑定可变的矩阵大小。
您也不需要像现在一样使用DX。 imul byte ptr matB[DI][BX]
可以工作,而无需单独加载到寄存器中。 (或使用指针imul byte ptr [BX]
。)这使您可以自由使用DX。