41 Востаннє редагувалося Betterthanyou (03.08.2017 04:12:29)

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Робота за матрицями
Задача
Вирішити систему лінійних алгебраїчних рівнянь за допомогою методу Крамера
Сама складна задача тут - це знайти визначник матриці.
Я використовую такі формули, вони дуже легко запам'ятовуються. (подивіться уважно і зрозумієте чому)
http://replace.org.ua/extensions/om_images/img/598277524f89e/Untitled.png
що до коду, то я створив дві функції, DERERMINANT2X2 - обчислює визначник 2х2, а також додатковий множник, DETERMINANT3X3 - обчислює визначник 3х3.
Аргументи записуються в спеціальному порядку, по мірі потрібності.
Ділення визначників - це доволі легка робота, тому тут все зрозуміло.
Для визначення максимально допустимого числа я взяв корінь з 32767, яке є максимально допустимим для числа зі знаком DW, хоча не знаю наскільки це правильно.
Також в програмі використовується регістр BP, не за призначенням, не знаю чи це погано, але для мене не вистачило регістрів загального призначення, тому я використав його (BP).

;CRAMER'S RULE
data segment
    ;Nothing more than +/-181!!!
    ;INSERT IN ORDER X11,X12,X13,B1,X21,X22,X23,B2,X31,X32,X33,B3
    ;------------------------------------------------------------
    ;Example:
    ;MATRIX DW 2, 5, 4, 30, 1, 3, 2, 150, 2, 10, 9, 110  
    ;MATRIX DW 1, 0, 1, 4, 0, 2, -1, 1, 3, -1, 0, 1
    ;MATRIX DW 1, 1, -2, 2, 2, -3, -1, 1, 1, -4, 1, 3; - ERROR
    MATRIX DW 2, 3, -1, 4, 1, 1, 3, 5, 3, -4, 1, 0
    X1 DW ?
    X2 DW ?
    X3 DW ?
ends

code segment 
    DETERMINANT3X3:          
    
    JMP DERERMINANT2X2
    MOV CX, AX
    JMP DERERMINANT2X2
    SUB CX, AX
    JMP DERERMINANT2X2
    ADD AX, CX
    RET

    DERERMINANT2X2:    
    
    POP BX    
    POP AX                
    IMUL BX
        
    MOV BP, AX
    POP BX
    POP AX       
    IMUL BX     
        
    SUB AX, BP
    MOV DX, AX
    POP AX    ;ADDITIONAL ACTION                
    IMUL DX
    RET 
start:
; set segment registers:
    mov ax, data
    mov ds, ax

    MOV SI, OFFSET MATRIX       
    ;
    ;----------------------------------
    ;A
    PUSH 05Dh; RETURN FROM DETERMINANT3X3
    ;
    PUSH 0Ah
    ;
    PUSH MATRIX[SI+4] ;a13
    PUSH MATRIX[SI+8] ;a21
    PUSH MATRIX[SI+18] ;a32
    PUSH MATRIX[SI+10] ;a22
    PUSH MATRIX[SI+16] ;a31
    ;
    PUSH 06h
    ;
    PUSH MATRIX[SI+2] ;a12
    PUSH MATRIX[SI+8] ;a21
    PUSH MATRIX[SI+20];a33
    PUSH MATRIX[SI+12] ;a23
    PUSH MATRIX[SI+16] ;a31
    ;
    PUSH 02h
    ;
    PUSH MATRIX[SI]   ;a11
    PUSH MATRIX[SI+10] ;a22
    PUSH MATRIX[SI+20];a33
    PUSH MATRIX[SI+12] ;a23
    PUSH MATRIX[SI+18] ;a32   
    
    JMP DETERMINANT3X3
    
    PUSH AX ;SAVE A
    ;
    ;----------------------------------
    ;A1
    MOV BX, 098h       
    PUSH BX; (DON'T WANT TO WORK WITH 09Bh) RETURN FROM DETERMINANT3X3
    ;
    PUSH 0Ah
    ;
    PUSH MATRIX[SI+4]   
    PUSH MATRIX[SI+14]   ;b2
    PUSH MATRIX[SI+18]
    PUSH MATRIX[SI+10]
    PUSH MATRIX[SI+22]   ;b3
    ;
    PUSH 06h
    ;
    PUSH MATRIX[SI+2]
    PUSH MATRIX[SI+14]   ;b2
    PUSH MATRIX[SI+20]
    PUSH MATRIX[SI+12]
    PUSH MATRIX[SI+22]   ;b3
    ;
    PUSH 02h
    ;
    PUSH MATRIX[SI+6]     ;b1
    PUSH MATRIX[SI+10] 
    PUSH MATRIX[SI+20]
    PUSH MATRIX[SI+12]
    PUSH MATRIX[SI+18]  
    
    JMP DETERMINANT3X3
    
    POP CX
    CWD    
    IDIV CX    
    MOV X1, AX
    PUSH CX
    ;
    ;----------------------------------
    ;A2
    MOV BX, 0D9h       
    PUSH BX; RETURN FROM DETERMINANT3X3
    ;
    PUSH 0Ah
    ;
    PUSH MATRIX[SI+4] ;a13
    PUSH MATRIX[SI+8] ;a21
    PUSH MATRIX[SI+22] ;b3
    PUSH MATRIX[SI+14] ;b2
    PUSH MATRIX[SI+16] ;a31
    ;
    PUSH 06h
    ;
    PUSH MATRIX[SI+6] ;b1
    PUSH MATRIX[SI+8] ;a21
    PUSH MATRIX[SI+20];a33
    PUSH MATRIX[SI+12] ;a23
    PUSH MATRIX[SI+16] ;a31
    ;
    PUSH 02h
    ;
    PUSH MATRIX[SI]   ;a11
    PUSH MATRIX[SI+14] ;b2
    PUSH MATRIX[SI+20];a33
    PUSH MATRIX[SI+12] ;a23
    PUSH MATRIX[SI+22] ;b3
    
    JMP DETERMINANT3X3
    
    POP CX
    CWD    
    IDIV CX    
    MOV X2, AX
    PUSH CX
    ;
    ;----------------------------------
    ;A3
    MOV BX, 011Ah       
    PUSH BX; RETURN FROM DETERMINANT3X3
    ;
    PUSH 0Ah
    ;
    PUSH MATRIX[SI+6] ;b1
    PUSH MATRIX[SI+8] ;a21
    PUSH MATRIX[SI+18] ;a32
    PUSH MATRIX[SI+10] ;a22
    PUSH MATRIX[SI+16] ;a31
    ;
    PUSH 06h
    ;
    PUSH MATRIX[SI+2] ;a12
    PUSH MATRIX[SI+8] ;a21
    PUSH MATRIX[SI+22];b3
    PUSH MATRIX[SI+14] ;b2
    PUSH MATRIX[SI+16] ;a31
    ;
    PUSH 02h
    ;
    PUSH MATRIX[SI]   ;a11
    PUSH MATRIX[SI+10] ;a22
    PUSH MATRIX[SI+22];b3
    PUSH MATRIX[SI+14] ;b2
    PUSH MATRIX[SI+18] ;a32
    
    JMP DETERMINANT3X3    
    
    POP CX
    CWD    
    IDIV CX    
    MOV X3, AX
    PUSH CX
    
    mov ax, 4c00h ; exit to operating system.
    int 21h    
ends            

end start ; set entry point and stop the assembler.

до речі, можливо це єдиний код Крамера на просторах інтернету, тому що мені не вдалося знайти інших прикладів вирішення.

42 Востаннє редагувалося koala (03.08.2017 07:35:31)

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Вашими функціями неможливо користуватися, як на мене.
Ви всі ці адреси (PUSH 05Dh, PUSH 06h і т.д.) вручну обчислювали? Хіба не логічніше було б поставити мітки в тих місцях, куди відбуваються переходи, і хоча б їх у стек пхати - не кажу вже про те, щоб описувати перед функцією вимоги до її виклику (стан регістрів і стеку)?

Подякували: 0xDADA11C7, Betterthanyou, leofun013

43

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Крамер на асмі для досу Теж лайно, але трохи краще.

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: Betterthanyou, leofun012

44 Востаннє редагувалося Betterthanyou (10.08.2017 23:06:09)

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

koala написав:

вручну обчислювали?

Так

koala написав:

Хіба не логічніше було б поставити мітки в тих місцях, куди відбуваються переходи, і хоча б їх у стек пхати - не кажу вже про те, щоб описувати перед функцією вимоги до її виклику (стан регістрів і стеку)?

Щось я про це не подумав, вже не хочу перероблювати.

Щодо вимог виклику функцій

DERERMINANT2X2 - для самостійного використання не призначена (спочатку там потрібно видалити додаткові операції, рядок 40)

DETERMINANT3X3 - Стан регістів не важливий, але регістри AX, BX, CX, DX, BP - будуть змінені.
Не записувати в 3-7,9-13,15-19 більше чим +/-181 (елементи матриці не можуть бути більші чим 181 - не вистаціть пам'яті для арифметики ).
В стеку повинні бути (перед цім можна записати AX, BX, CX, DX, BP в стек, щоб потім їх відновити):
1 - куди повернутися після завершення роботи функції
2 - адреса рядка "ADD AX, CX" функції "DERERMINANT2X2"
3 - елемент (комірка) матриці a13
4 - елемент (комірка) матриці a21
5 - елемент (комірка) матриці a32
6 - елемент (комірка) матриці a22
7 - елемент (комірка) матриці a31
8 - адреса рядка "SUB CX, AX" функції "DERERMINANT2X2"
9 - елемент (комірка) матриці a12
10 - елемент (комірка) матриці a21
11 - елемент (комірка) матриці a33
12 - елемент (комірка) матриці a23
13 - елемент (комірка) матриці a31
14 - адреса рядка "MOV CX, AX" функції "DERERMINANT2X2"
15 - елемент (комірка) матриці a11
16 - елемент (комірка) матриці a22
17 - елемент (комірка) матриці a33
18 - елемент (комірка) матриці a23
19 - елемент (комірка) матриці a32
Результат виконання функції буде в регістрі АХ, тобто визначник матриці

45 Востаннє редагувалося Betterthanyou (11.08.2017 00:26:24)

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

reverse2500 написав:

ще

CALL [ESP]

еквівалент

RET

Перевірив

P2 PROC         
CALL [SP]

Помилка
"wrong parameters: CALL [SP]"

Що означають [] (квадратні дужки) ? - Я подивився що це адрес операнда (а не значення стеку), а для того щоб подивитися значення стек потрібно використати команду "top" (top: отримати верхній елемент (без виштовхування).) - якої в асемблері немає. Звісно що я ще не достатньо добре знаю асемблер, тому якщо я помилився - поправте мене

koala написав:

CALL - це PUSH+JMP, а RET - це POP+JMP.

Якщо ж використати "POP", то виходить замінити ret на call - але навіщо тоді це

P2 PROC        
        POP AX 
CALL AX;В стек появиться адрес AX який потім потрібно буде виштовхнути 

46 Востаннє редагувалося koala (11.08.2017 09:24:41)

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Стосовно квадратних дужок - є різні асемблери з різними позначеннями; квадратні дужки зазвичай означають непряму адресацію, тобто "взяти адресу операнду в тому, що стоїть в квадратних дужках".
RET, ще раз, це повний аналог POP IP (напряму так не можна).
Ну і https://edge.edx.org/c4x/BITSPilani/EEE … ual_1_.pdf

Подякували: Betterthanyou, leofun012

47 Востаннє редагувалося Betterthanyou (12.08.2017 05:19:44)

Re: [Асемблер8086]Від нуба до професіонала(або шлях на асемблерну вершину)

Логічні команди та їх використання
Задача
Задано двадцять однобайтових кодів, у кожному коді, у якому розряди 3,4,5,6,7 дорівнюють відповідно  1,1,0,0,1, поміняти всі розряди на протилежні, якщо ж вказана умова не виконується, то парні розряди поміняти на протилежні, а непарні встановити в нуль.

- Для початку потрібно видалити (встановити в нуль) 0,1,2 розряди коду, щоб легко порівняти код з 1,1,0,0,1, для цього я виконую дію "and" над маскою і кодом. (рядок 22-23)
- Порівняти маску "00011001" і код, в якому вже 0,1,2 розряди встановлені в нуль (рядок 24)
- Відновити початковий код (рядок 25)
- В задачі є схоже завдання в обох розгалуженнях - це поміняти розряди на протилежні, тож цю дію варто виконати перед розгалуженням JE (рядок 26)
- Якщо код і маска "00011001" не є рівними, то непарні розряди зануляться, для встановлення непарним розрядам нуль, потрібно виконати дію "and" над маскою "10101010" і кодом. Дія "not" вже виконана перед цим (рядок 29)

data segment
    ARR1 DB 74d, 225d, 84d, 12d, 36d, 99d, 74d, 124d, 87d, 144d, 223d, 177d, 8d, 41d, 160d, 133d, 154d, 111d, 249d, 20d
    SIZE_OF_ARR1 DB $-ARR1
ends
code segment
start:
; set segment registers:
    mov ax, data
    mov ds, ax
    
    MOV BL, 01Fh ;MASK 00011111b (OR 01Fh)
    MOV BH, 019h ;MASK 00011001b (OR 019h)
    MOV DL, 0AAh ;MASK 10101010 (OR 0AAh)
    
    ;SETUP SIZE OF ARR1
    MOV CH, 0                        
    MOV CL, SIZE_OF_ARR1            
    MOV SI, CX
    DEC SI;START WITH 19 ELEMENT
    
    LOOP1:
    MOV AH, ARR1[SI];SETUP VALUE
    AND AH, BL      ;USE A MASK FOR DELETE THE FIRST THREE BITS
    CMP AH, BH      ;COMPARE THIS BYTE AND A MASK
    MOV AH, ARR1[SI];SETUP AGAIN THE SAME BYTE (VALUE) IN ORDER TO RESTORE THE FIRST THREE BITS
    NOT AH                          
    JE EQUAL
    ;DO NOT EQUAL
    AND AH, DL
    EQUAL:                              
    MOV ARR1[SI], AH
    DEC SI
    LOOP LOOP1
    
    mov ax, 4c00h ; exit to operating system.
    int 21h    
ends

end start ; set entry point and stop the assembler.