Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Asm для начинающих > Обработка массива


Автор: bncom 15.4.2007, 19:40
Здравствуйте!

Вот код, который находит максимальный элемент в массиве.

Код

.MODEL SMALL

;----------Сегмент стека------------
STACKSG SEGMENT PARA STACK 'stack'
        DB      256  DUP(?)  
STACKSG ENDS
;-----------------------------------

;----------Сегмент данных-----------
DATASG  SEGMENT PARA  'data'
NUMBER  DW     5
MASSIV  DW     0,3,-6,34,10    
REZ     DB     ?
DATASG  ENDS
;----------------------------------

;----------Сегмент кода------------
CODESG  SEGMENT PARA 'Code'
        ASSUME  CS:CODESG, DS:DATASG, SS:STACKSG 

MAIN    PROC    FAR

    PUSH    DS           ; Подготовка к
    SUB     AX,AX         ; возврату в
    PUSH    AX         ; ОС

    MOV    AX, DATASG    ; Настраиваем регистр DS на
    MOV    DS,AX        ; сегмент данных

    MOV     AX,NUMBER    ; 
    LEA     SI,MASSIV    ; Загружаем адрес MASSIV в регистр индекса источника SI
    PUSH    SI        ; Заносим адрес начала массива к стек
    PUSH    AX        ; Заносим количество элементов в стек
    CALL    MAX_EL        ; Вызов подпрограммы поиска максимального элемента
    MOV    REZ,AX        ; Заносим результат в REZ
    ;MOV     BX,AX
    ;MOV     AL,BX
    ;MOV     REZ,AL
    RET              ; Завершение работы
MAIN    ENDP

MAX_EL    PROC    NEAR
    PUSH    BP        ; Сохраняем старое значение указателя базы кадров стека BP
    MOV    BP,SP        ; Ставим указатель BP на указатель стека SP
    MOV    CX,[BP+4]    ; Количество элементов массива
    MOV    SI,[BP+6]    ; Адрес массива
    MOV    AX,[SI]        ; Максимальный элемент массива
For:    MOV     BX,[SI]        ; Помещаем в регистр BX элемент массива
    CMP    BX,AX        ; Сравниваем текущий элемент с максимальным
    JS      End_if        ; Если BX < MAX, то переходим к метке End_if
    MOV     AX,BX        ; Иначе AX=BL
End_if: ADD     SI,2        ; Переходим к следующему элементу массива
    LOOP    For        ; CX-=1, если CX!=0, то переходим к метке For
    POP    BX        ; Восстанавливаем значение BP
    RET    4
MAX_EL    ENDP

CODESG  ENDS
        END    MAIN


Мне надо, чтоб результат заносился не в регистр AX (как в сейчас), а в регистр AL. 
Я пробывал, но что-то не получается, выдаются ошибки... ((

Помогите пожалуйтса....

Автор: JAPH 15.4.2007, 20:07
Sorry, а как вы собираетесь запихнуть 16-битный элемент массива в 8-битный AL?!
В строке 54 POP BP smile

Автор: bncom 16.4.2007, 08:42
Цитата

Sorry, а как вы собираетесь запихнуть 16-битный элемент массива в 8-битный AL?!
Ну вот такое задание, что поделаешь...
Так может быть кое-что тогда изменить надо?

Автор: JAPH 16.4.2007, 12:17
Элементы массива обязательно word? Сделайте их DB ..., поиск максимума перепишите с использованием 8-битных регистров.

Автор: bncom 16.4.2007, 16:52
JAPH, сделал как вы подсказали - в результате получается какой-т обесконечный цикл...

Код

.MODEL SMALL

;----------Сегмент стека------------
STACKSG SEGMENT PARA STACK 'stack'
        DB      256  DUP(?)  
STACKSG ENDS
;-----------------------------------

;----------Сегмент данных-----------
DATASG  SEGMENT PARA  'data'
NUMBER  DB     5
MASSIV  DB     0,3,-6,34,10    
REZ     DB     ?
DATASG  ENDS
;----------------------------------

;----------Сегмент кода------------
CODESG  SEGMENT PARA 'Code'
        ASSUME  CS:CODESG, DS:DATASG, SS:STACKSG 

MAIN    PROC    FAR

    PUSH    DS           ; Подготовка к
    SUB     AX,AX         ; возврату в
    PUSH    AX         ; ОС

    MOV    AX, DATASG    ; Настраиваем регистр DS на
    MOV    DS,AX        ; сегмент данных

    MOV     AL,NUMBER    ; 
    LEA     SI,MASSIV    ; Загружаем адрес MASSIV в регистр индекса источника SI
    PUSH    SI        ; Заносим адрес начала массива к стек
    PUSH    AX        ; Заносим количество элементов в стек
    CALL    MAX_EL        ; Вызов подпрограммы поиска максимального элемента
    MOV    REZ,AL        ; Заносим результат в REZ
    RET              ; Завершение работы
MAIN    ENDP

MAX_EL    PROC    NEAR
    PUSH    BP        ; Сохраняем старое значение указателя базы кадров стека BP
    MOV    BP,SP        ; Ставим указатель BP на указатель стека SP
    MOV    CX,[BP+4]    ; Количество элементов массива
    MOV    SI,[BP+6]    ; Адрес массива
    MOV    AL,[SI]        ; Максимальный элемент массива
For:    MOV     BL,[SI]        ; Помещаем в регистр BX элемент массива
    CMP    BL,AL        ; Сравниваем текущий элемент с максимальным
    JS      End_if        ; Если BX < MAX, то переходим к метке End_if
    MOV     AL,BL        ; Иначе AX=BL
End_if: ADD     SI,2        ; Переходим к следующему элементу массива
    LOOP    For        ; CX-=1, если CX!=0, то переходим к метке For
    POP    BP        ; Восстанавливаем значение BP
    RET    4
MAX_EL    ENDP

CODESG  ENDS
        END    MAIN


У меня в массиве всего 5 элементов, а цикл проходит более 50 раз и дальше...


Автор: JAPH 16.4.2007, 17:52
Цитата
Код
MOV  AL, NUMBER
...
PUSH AX

А в AH у вас что? Остаток DSEG?
Вставьте XOR AH, AH.
Да, и ещё INC SI в строке 49.

Автор: bncom 17.4.2007, 09:09
Опять же такая проблема (подправил как вы подсказали).

Код

.MODEL SMALL

;----------Сегмент стека------------
STACKSG SEGMENT PARA STACK 'stack'
        DB      256  DUP(?)  
STACKSG ENDS
;-----------------------------------

;----------Сегмент данных-----------
DATASG  SEGMENT PARA  'data'
NUMBER  DB     5
MASSIV  DB     0,3,-6,34,10    
REZ     DB     ?
DATASG  ENDS
;----------------------------------

;----------Сегмент кода------------
CODESG  SEGMENT PARA 'Code'
        ASSUME  CS:CODESG, DS:DATASG, SS:STACKSG 

MAIN    PROC    FAR
     PUSH    DS            ; Подготовка к
     SUB     AX,AX          ; возврату в
     PUSH    AX          ; ОС

     MOV     AX, DATASG     ; Настраиваем регистр DS на
     MOV     DS,AX         ; сегмент данных

     MOV     AL,NUMBER     ; 
     LEA     SI,MASSIV     ; Загружаем адрес MASSIV в регистр индекса источника SI
     PUSH    SI        ; Заносим адрес начала массива к стек
     XOR    AX,AX
     PUSH    AX         ; Заносим количество элементов в стек
     
     CALL    MAX_EL         ; Вызов подпрограммы поиска максимального элемента
     MOV     REZ,AL         ; Заносим результат в REZ
     RET               ; Завершение работы
MAIN    ENDP

MAX_EL  PROC    NEAR
     PUSH    BP         ; Сохраняем старое значение указателя базы кадров стека BP
     MOV     BP,SP      ; Ставим указатель BP на указатель стека SP
     MOV     CX,[BP+4]    ; Количество элементов массива
     MOV     SI,[BP+6]     ; Адрес массива
     MOV     AL,[SI]         ; Максимальный элемент массива
For:    MOV     BL,[SI]         ; Помещаем в регистр BX элемент массива
     CMP     BL,AL         ; Сравниваем текущий элемент с максимальным
     JS      End_if         ; Если BX < MAX, то переходим к метке End_if
     MOV     AL,BL         ; Иначе AL=BL
     INC    SI 
End_if: ADD     SI,2         ; Переходим к следующему элементу массива
     LOOP    For         ; CX-=1, если CX!=0, то переходим к метке For
     POP     BP         ; Восстанавливаем значение BP
     RET     4
MAX_EL  ENDP

CODESG  ENDS
        END    MAIN


Когда начинаю трассировать в ручном режиме - как буд-то все нормально. Максимальный элемент заносится в AX (хотя, по-идеи он должен быть в AL, но я не знаю где смотреть AL в Turbo Debbager'е), а дальше опять какой-т обесконечный цикл...
 smile 

Можетя я что-то не туда вставляю?

 smile 

Автор: sgi1981 17.4.2007, 11:46
Код

.MODEL SMALL
;----------Сегмент стека------------
STACKSG SEGMENT PARA STACK 'stack'
        DB      256  DUP(?)  
STACKSG ENDS
;-----------------------------------
;----------Сегмент данных-----------
DATASG  SEGMENT PARA  'data'
NUMBER  DW     5
MASSIV  DB     0,3,-6,34,10    
REZ     DB     ?
DATASG  ENDS
;----------------------------------
;----------Сегмент кода------------
CODESG  SEGMENT PARA 'Code'
        ASSUME  CS:CODESG, DS:DATASG, SS:STACKSG 
MAIN    PROC    FAR
    PUSH    DS           ; Подготовка к
    SUB     AX,AX         ; возврату в
    PUSH    AX         ; ОС
    MOV    AX, DATASG    ; Настраиваем регистр DS на
    MOV    DS,AX        ; сегмент данных
    MOV     AX,NUMBER    ; 
    LEA     SI,MASSIV    ; Загружаем адрес MASSIV в регистр индекса источника SI
    PUSH    SI        ; Заносим адрес начала массива к стек
    PUSH    AX        ; Заносим количество элементов в стек
    CALL    MAX_EL        ; Вызов подпрограммы поиска максимального элемента
    MOV    REZ,AL        ; Заносим результат в REZ
    RET              ; Завершение работы
MAIN    ENDP

MAX_EL    PROC    NEAR
    PUSH    BP        ; Сохраняем старое значение указателя базы кадров стека BP
    MOV    BP,SP        ; Ставим указатель BP на указатель стека SP
xor dx, dx;обнулить регистры для исключения влияния старших частей регистров
xor ax, ax;
    MOV    CX,[BP+4]    ; Количество элементов массива
    test cx, cx;предотвращение 
    jz @error55;ошибки при количестве элементов массива = 0
    MOV    SI,[BP+6]    ; Адрес массива
    MOV    DL,[SI]        ; Максимальный элемент массива
dec cx;количество остальных элементов массива на 1 меньше
jcxz @error55;если массив состоит из одного элемента - обходим цикл
cld;выполнение цепочечных команд с увеличением адреса адресных регистров
inc si;переходим на следующий элемент массива
For:;цикл
lodsb; Помещаем в регистр AL элемент массива и смещает указатель si на один байт 
;(ah и dh  равны 0)
cmovl dx, ax;если dx меньше ax - помещает dx=ax
loop  For;
@error55:
mov ax, dx;вернуть максимальный элемент в ax (на самом деле эффективно записывается al)
    POP    BX        ; Восстанавливаем значение BP
    RET    4
MAX_EL    ENDP
CODESG  ENDS
        END    MAIN

Автор: bncom 18.4.2007, 16:54
sgi1981, спасибо большое!
У вас даже лучше получилось: предусмотрели "защиту" от дурака как говорят...

Но на 49 строчке (cmovl dx, ax)у меня выдает ошибку.

Ошибка в команде видимо, т.к. CMOVL делает пересылку значения источника в приемник, если флаги SF<>OF.

Или еще в чем-то....

Автор: JAPH 18.4.2007, 19:46
Цитата
Можетя я что-то не туда вставляю?

Конечно, не туда! Точнее, не то smile
XOR AH, AH, а не XOR AX, AX!
INC SI вместо ADD SI, 2.

Цитата
где смотреть AL в Turbo Debbager'е

AL - младший байт AX. AX вы знаете где. Две младшие его цифры и есть AL; две старшие, кстати, AH.

Цитата
Или еще в чем-то....

В том, что CMOVxx появилась в Pentium Pro.

Код

; А зачем .MODEL? Мы же полностью определяем сегменты
        .186
STACKSG SEGMENT PARA STACK 'stack'
        DB      256  DUP(?)
STACKSG ENDS
DATASG  SEGMENT PARA  'data'
NUMBER  DW     5
MASSIV  DB     0,3,-6,34,10
REZ     DB     ?
DATASG  ENDS
CODESG  SEGMENT PARA 'Code'
        ASSUME  CS:CODESG, DS:DATASG, SS:STACKSG
MAIN    PROC    FAR
        PUSH    DS
        PUSH    0
        MOV     AX, DATASG
        MOV     DS, AX
        PUSH    offset MASSIV
        PUSH    NUMBER
        CALL    MAX_EL
        MOV     REZ, AL
        RET
MAIN    ENDP
MAX_EL  PROC    NEAR
        PUSH    BP
        MOV     BP, SP
        MOV     CX, [BP+4]
        MOV     SI, [BP+6]
        MOV     AL, [SI]
For:    DEC     CX
        JZ      End_for
        CMP     AL, [SI]
        JG      End_if
        MOV     AL, [SI]
End_if: INC     SI
        JMP     For
End_for:POP     BP
        RET     4
MAX_EL  ENDP
CODESG  ENDS
        END    MAIN

Автор: sgi1981 19.4.2007, 11:33
To bncom:
напиши в самом начале директиву
.586p

Автор: bncom 19.4.2007, 13:13
Все сделал - все получилось! =)

Большое всем спасибо!  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)