Сборка 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 бесплатно.

Другие вопросы по тегам