Сборка 8086 - умножить две матрицы
Этот кусок кода должен умножить две матрицы, сохраняя знак соответствующих элементов
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, потому что эмулятор вычисляет неправильное смещение.
1 ответ
matB[DI][BX]
не 2D индексация, это просто matB[DI + BX]
, Я не знаю, почему emu8086 поддерживает этот запутанный синтаксис, но я бы не стал его рекомендовать.
Машинный код 8086 поддерживает только простое добавление в режимах адресации, поэтому вам нужно что-то вроде add DI, N
шагать через вектор столбца.
Под
decM
: Мне пришлось переместить значение BP в BX, потому что эмулятор вычисляет неправильное смещение.
Это странно. Сначала я задавался вопросом, было ли у вас правильное смещение, но неправильная база сегмента (потому что BP подразумевает SS, а BX подразумевает DS), но .model small
дает вам DS = SS.
Но я думаю, что вам нужно инициализировать DS самостоятельно. Если я правильно понимаю, DOS .exe
начинается с базы DS = начало PSP. Почему MS-DOS не инициализирует регистры DS и ES? ,
Таким образом, у вас, вероятно, правильное смещение, но неправильная база сегмента, что приводит к неправильному линейному адресу. Если BP
работает, то это не смещение, что неправильно в seg:off
режим адресации.
Как только вы исправите это, вы сможете отлаживать свой код с помощью отладчика. Сегменты могут сбивать с толку, но остальные должны быть легко отлажены, пошагово, и поискать любые удивительные инструкции в руководстве.
[BP+BX]
неверный режим адресации, так что да, вам нужно MOV SI,BP
до ADD matC[BX][SI],AX
, Или же add bx,bp
или что-то, если вы можете забить регистр.
Вы можете просто увеличить 3 указателя (назначение, источник столбца и источник строки) с inc
или же add reg,N
/ sub reg,P-1
или что-то еще, вместо того, чтобы пытаться сохранить 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 бесплатно.