сборка 8086 - умножить две матрицы - PullRequest
0 голосов
/ 01 ноября 2018

Этот фрагмент кода должен умножить две матрицы, сохраняя знак соответствующих элементов

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 Ответ

0 голосов
/ 02 ноября 2018

matB[DI][BX] - это не двумерная индексация, а просто matB[DI + BX]. Я не знаю, почему emu8086 поддерживает этот запутанный синтаксис, но я бы не рекомендовал его.

Машинный код

8086 поддерживает только простое добавление в режимах адресации, поэтому вам нужно что-то вроде add DI, N для перемещения по вектору столбца.

Под decM: мне пришлось переместить значение BP в BX, потому что эмулятор вычисляет неправильное смещение.

Странно. Сначала я задавался вопросом, было ли у вас правильное смещение, но неправильная база сегмента (потому что BP подразумевает SS, а BX подразумевает DS), но .model small дает вам DS = SS .

Но я думаю, что вам нужно инициализировать DS самостоятельно. Если я правильно понимаю, DOS .exe начинается с DS base = start of 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-доступом.


Несбалансированный push / pop

Ваш внутренний цикл имеет 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.

...