Седов Иван Алексеевич

Рязанский политехнический колледж

ASSEMBLER 8-bit SIMULATOR

Занятие #8: создание процедуры

сортировка массива по возрастанию

 

https://e1m7.github.io/work/

Последнее занятие по ассемблеру будет посвящено сложной и интересной процедуре сортировки одномерного массива по возрастанию. Для решения этой задачи мы напишем несколько вспомогательных процедур, которые позволят решить эту задачу за пару шагов

 

  • процедура array_print (вывод массива)
  • процедура array_length (нахождение длины массива)
  • процедура array_sort (сортировка массива)

 

Для простоты мы договоримся, что массив это набор байт, каждый из которых является числом от 0 до 9. Можно задавать полные байты (0-255), но выводить массив на печать будет не удобно. (Однако, в оперативной памяти массив упорядочится верно.)

Суть программы будет такова:

 

1) Получаем адрес массива (байты 48-57), на конце '#' (код 35)

2) Находим длину массива (нужна для сортировки)

3) Выводим массив на экран (экран: 2 1 3)

4) Сортируем по возрастанию (магия)

5) Выводим массив на экран (экран: 1 2 3)

array: DB 2
       DB 1
       DB 3
       DB '#'
; 2 1 3 (до сортировки)
; 1 2 3 (после сортировки)
array_print:
; input
; C = array of number, '#'
  PUSH A
  PUSH C
  PUSH D
  MOV D, 232    ; D=232 (настройка на байты вывода)
.loop100:
  MOV A, [C]    ; A=байт, адрес которого в C
  ADD A, '0'    ; A=A+'0'=значение байта + 48
  CMP A, 83     ; Сравнение: A=83? 83=35(#)+48(0)
  JE .exit101   ; (да) переход на .exit101
  MOV [D], A    ; (нет) байт, адрес которого в D=A
  INC D         ; D=D+1
  INC C         ; C=C+1
  JMP .loop100
.exit101:
  POP D
  POP C
  POP A
  RET

Вопрос: а зачем нам нужна процедура array_length? Да, она найдет нам длину массива (допустим, он состоит из 6 элементов). Но давайте разберемся...

 

 

 

 

Если мы будем брать текущий индекс элемента и сравнивать значение текущего элемента и значение следующего элемента, то какой индекс будет для нас "остановочным"? 

Если на 6-ом месте (под индексом 5) стоит минимальное число (в данном случае 1), то сколько проходов-сравнений надо будет сделать, чтобы она встала на 1-ое место (под индексом 0)?

arr: DB 6, 5, 4, 3, 2, 1, #
;       0  1  2  3  4  5  6
array_length:
; input
; C = array of number, '#'
; output
; A = length array
  PUSH B
  PUSH C
  XOR A, A      ; A=0 (XOR 11=>0, 10=>1, 01=>1, 00=>0)
.loop110:
  MOV B, [C]    ; B=байт, адрес которого в С
  CMP B, 35     ; Сравнение: B=35? (это решетка?)
  JE .exit111   ; (да) перейти на выход 
  INC A         ; (нет) A=A+1 (накопить счетчик)
  INC C         ; С=С+1 (перейти на следующий элемент)
  JMP .loop110
.exit111:
  DEC A         ; A=A-1 (нам нужно именно это число)
  POP C
  POP B
  RET

Процедура array_sort оказалась длинной (вся программа 173 байта, 130 строк кода), записывать ее лучше сразу с основной программой (надо будет добавить две ранее записанные процедуры array_print и array_length в самый низ).

JMP start
arr: DB 6
     DB 5
     DB 4
     DB 3
     DB 2
     DB 1
     DB '#'
len:  DB 0
start:
  MOV C, arr
  CALL array_length
  MOV [len], A
  CALL array_print   ; Вывод массива
  CALL array_sort    ; Сортировка
  CALL array_print   ; Вывод массива
  HLT

array_sort:
; input
; C = array of number, '#'
; len = length - 1
  PUSH A
  PUSH B
  PUSH C
  PUSH D
  ; Внешний цикл
  MOV C, 0
  .loop600:
  CMP C, [len]
  JE .exit601

    ; Внутренний цикл
    MOV D, 0
    .loop602:
    CMP D, [len]
    JE .exit602

    ; Извлечение чисел
    MOV A, arr     ; A=arr (адрес)
    ADD A, D       ; A=A+D (адрес + смещение)
    MOV B, [A]     ; B=по адресу A (1-ое число)
    PUSH B         ; 1 число => в стек
    MOV B, [A+1]   ; B=по адресу A+1 (2-ое число)  
    POP A          ; 1 число <= из стека
    ; A=1-ое число (текущее)
    ; B=2-ое число (текущее+1)
  
    ; Сравнение чисел
    CMP A, B       ; Сравнить: A>B?
    JA .change666  ; (да) переход .change666 
    JMP .exit666   ; (нет) переход .exit666

    ; Обмен чисел
    .change666:
    PUSH A         ; 1 => стек
    PUSH B         ; 2 => стек (2,1)
    MOV A, arr     ; A=arr (адрес)
    ADD A, D       ; A=A+D (адрес + смещение)
    POP B          ; B=2-ое число
    MOV [A], B     ; Адрес 1 = 2 число
    POP B          ; B=1-ое число
    MOV [A+1], B   ; Адрес 2 = 1 число
    .exit666:
    INC D
    JMP .loop602
    ; Внутренний цикл

  .exit602:
  INC C
  JMP .loop600
  ; Внешний цикл

.exit601:
  POP D
  POP C
  POP B
  POP A
  RET
  • print_string
  • print_number

  • print_char

  • remainder_division
  • remdiv10

  • halt
  • string_to_number
  • number_to_string
  • factorial
  • fibonachi
  • array_print
  • array_length
  • array_sort


Замечание

В нашем распоряжении есть процедуры:

Введение в программирование окончено!!!

assembler8_08

By Ivan Sedov

assembler8_08

  • 462