М. Иванюшин

Учимся программировать


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

     Сложение
     Для сложения однобайтных чисел в наборе команд микропроцессора КР580ВМ80А есть стандартные команды ADD и ADC, сложение двухбайтных чисел выполняется при помощи команды DAD. Но если складываемые числа превосходят два байта, то для сложения надо писать специальную программу. Приведенная ниже программа складывает трехбайтные числа:

;СЛОЖЕНИЕ ТРЕХБАЙТНЫХ ЧИСЕЛ
;вход в программу:
;первое слагаемое SL0, SL1, SL2;
;второе слагаемое SL3, SL4, SL5;
;результат работы:
;сумма SL3, SL4, SL5;

SUMMA3:   LHLD SLO
          XCHG         ;D,E - младшие 
                       ;байты первого 
                       ;слагаемого
          LHLD SL3     ;H,L - младшие
                       ;байты второго 
                       ;слагаемого
          DAD D        ;H,L - сумма этих 
                       ;младших байтов. 
                       ;Если при сложении 
                       ;возникнет перенос, 
                       ;он будет в даль-
                       ;нейшем учтен в 
                       ;команде ADC M
          SHLD SL3     ;сохранили в памяти 
                       ;первые два 
                       ;байта результата
          LDA SL2      ;в регистре А 
                       ;старший байт 
                       ;первого слагаемого
          LXI H,SL5    ;H,L - адрес 
                       ;старшего байта
                       ;второго слагаемого
          ADC M        ;сложение старших 
                       ;байтов слагаемых. 
                       ;Учтен перенос, 
                       ;если он был при 
                       ;сложении командой DAD
          MOV M,A      ;результат в SL5
          RET

     Вычитание
     Для вычитания в наборе команд микропроцессора есть две команды SUB и SBB, работают они только с байтами, для обработки же многобайтных чисел надо писать программу. Вычитание одного двухбайтного числа из другого можно организовать, например, так:

;ВЫЧИТАНИЕ ДВУХБАЙТНЫХ ЧИСЕЛ
;вход в программу:
;H,L - уменьшаемое, 
;D,E - вычитаемое,
;результат работы:
;В,С - разность.

VICH2:    MOV A,L 
;ВЫЧИТАНИЕ МЛАДШИХ БАЙТОВ 
          SUB E 
          MOV С,А
;ВЫЧИТАНИЕ СТАРШИХ БАЙТОВ 
          MOV А,Н
          SBB D     ;учитывается перенос,
                    ;если он был 
                    ;при обработке 
                    ;младших байтов 
          MOV В,А 
          RET

     Для вычисления разности трехбайтных чисел можно использовать следующую программу:

;ВЫЧИТАНИЕ ТРЕХБАЙТНЫХ ЧИСЕЛ
;вход в программу:
;уменьшаемое SL3,SL4,SL5,
;вычитаемое SL0,SL1,SL2,
;результат работы:
;разность SL3,SL4,SL5.

VICH3:    LXI H,SL0    ;HL - адрес млад-
                       ;шего байта
                       ;вычитаемого 
          LXI D,SL3    ;DE - адрес млад-
                       ;шего байта
                       ;уменьшаемого 
          LDAX D       ;A - младший байт
                       ;уменьшаемого 
          SUB М 
          STAX D       ;вычислен и сохранен
                       ;младший байт
                       ;разности 
          INX D        ;DE - адрес байта SL4 
          INX H        ;HL - адрес байта SL1
          LDAX D 
          SBB M 
          STAX D       ;в SL4 второй байт
                       ;разности 
          INX H 
          INX D 
          LDAX D 
          SBB M 
          STAX D       ;в SL5 третий байт
                       ;разности 
          RET

     Умножение
     Микропроцессор КР580ВМ80А не имеет команд умножения, поэтому для выполнения этой математической операции надо составлять программу.

     Приведенная здесь программа работает по следующему алгоритму:
     Шаг 1: проверить младший бит множителя. Если он равен нулю, перейти к шагу 3, если единице - сложить множимое с промежуточным результатом умножения.
     Шаг 2: сдвинуть полученный промежуточный результат на один бит влево.
     Шаг 3: повторять шаги 1 и 2 до тех пор, пока не будут проверены все биты множителя.

;УМНОЖЕНИЕ
;вход в программу: 
;А - множитель, DE — множимое, 
;результат работы: 
;HL - произведение

UMNOG:    LXI Н,0     ;сброшен промежу-
                      ;точный результат
     ;****** шаг 3 ******
SHAG3:    ORA А       ;проверка оконча-
                      ;ния работы
          RZ          ;если содержимое 
                      ;регистра А 
                      ;равно нулю - 
                      ;умножение закончено
     ;****** шаг 1 ******
          RAR         ;младший бит мно-
                      ;жителя в переносе
          INC SDVIG   ;если перенос 
                      ;равен нулю - 
                      ;пропуск сложения
          DAD D       ;сложение множи-
                      ;мого и промежуточ-
                      ;ного результата 
      ;******шаг 2 ******
SDVIG:    XCHG
          DAD H       ;сдвиг множимого
          XCHG
          JMP SHAG3

     В строке с меткой SHAG3 проверка на равенство нулю аккумулятора выполнена при помощи логической операции ИЛИ аккумулятора с самим собой. Эта операция не изменяет содержимое аккумулятора, но устанавливает все признаки. Можно было бы проверить содержимое аккумулятора на равенство нулю при помощи команды CPI 00, но эта команда занимает больше места в памяти и дольше выполняется.

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

;ДЕЛЕНИЕ ЧЕТЫРЕХБАЙТНОГО ЧИСЛА 
;НА ЧЕТЫРЕХБАЙТНОЕ
;вход в программу: 
;DE - адрес делимого, 
;HL - адрес делителя, 
;результат работы: 
;RES —частное, 
;DE — адрес остатка. 

DELEN:    XRA А
          STA RES
          STA RES+1
          STA RES+2
          STA RES+3    ;сброшено значение 
                       ;частного
;ЗАПИСЬ ДЕЛИТЕЛЯ В ЯЧЕЙКУ DEL
          MOV A,M
          STA DEL
          INX H
          MOV A,M
          STA DEL+1
          INX H
          MOV A,M
          STA DEL+2
          INX H
          MOV A,M
          STA DEL+3
          INX H
          MOV A,M
          STA DEL+4
          LXI H,RES
;вычитание делимого из делителя
Rl:       LDA DEL
          MOV C,A
          LDA DEL+1
          MOV B,A
          LDAX D
          SBB С
          STAX D
          INX D
          LDAX D
          SBB В
          STAX D
          INX D
          LDA DEL+2
          MOV C,A
          LDA DEL+3
          MOV B,A
          LDAX D
          SBB С
          STAX D
          INX D
          LDAX D
          SBB В
          STAX D
          DCX D
          DCX D
          DCX D        ;восстановлено 
                       ;исходное значение 
                       ;регистров DE
          JC KD        ;если перенос уста-
                       ;новлен, значит 
                       ;делитель стал 
                       ;больше делимого
          PUSH PSW     ;запомнено состояние 
                       ;переноса
;подсчет числа вычитаний 
;делителя из делимого 
;HL - адрес результата
DELI:     INR M
          JNZ R3
          INX H        ;если установлен 
                       ;признак равенства 
                       ;нулю, значит, в 
                       ;результате выполнения
                       ; команды INR M
                       ;возник перенос и 
                       ;его надо учесть
          INR М        ;увеличен на единицу
                       ;следующий байт 
                       ;результата
          JNZ R2
          INX H
          INR M
          DCX H        ;восстановление 
                       ;исходного значения
R2:       DCX H        ;регистров HL 
R3:       POP PSW      ;восстановлен 
                       ;текущий перенос 
                       ;для правильного 
                       ;выполнения сложения 
                       ;в цикле R1
          JMP R1
;ВОССТАНОВЛЕНИЕ ОСТАТКА
KD:       LDA DEL
          MOV C,A
          LDA DEL+1
          MOV B,A
          LDAX D
          ADD С
          STAX D
          INX D
          LDAX D
          ADC В
          STAX D
          INX D
          LDA DEL+2
          MOV C,A
          LDA DEL+3
          MOV B,A
          LDAX D
          ADC С
          STAX D
          INX D
          LDAX D
          ADC В
          STAX D
          DCX D
          DCX D
          DCX D        ;DE - адрес остатка
          RET

     Преобразование чисел
     Люди привыкли работать с десятичными числами, а вычислительные машины работают только с двоичными, поэтому, если требуется отображать результаты работы ЭВМ в десятичном виде или преобразовывать вводимые десятичные числа в двоичный формат, необходимы специальные программы.
     В вычислительной технике есть понятие двоично-десятичного числа. Двоично-десятичным числом называется число, в котором каждые четыре бита представляют десятичную цифру от 0 до 9. Например, двоичное число 00001111 в двоично-десятичном виде будет 00010101.
     Суть описываемой программы преобразования двоичного числа в двоично-десятичное заключается в том, что двоичное число, которое в обычном виде выглядит так:

      двоичное число:
              бит7 * 27 + бит6 * 26 + бит5 * 25 + бит4 * 24 +
             + бит3 * 23 + бит2 * 22 + бит1 * 21 + бит0 * 20
преобразуется к виду:
      десятичное число:
           ((((((бит7 * 2 + бит6) * 2 + бит5) * 2 + бит4) * 2 + 
                + бит3) * 2 + бит2) * 2 + бит1) * 2 + бит0.



;ПРЕОБРАЗОВАНИЕ ДВОИЧНОГО ЧИСЛА 
;В ДВОИЧНО-ДЕСЯТИЧНОЕ
;BCD2B - программа перевода двухбайтного
;двоичного числа в двоично-десятичное.
;Двоичное число передается
;в регистрах HL, 
;результат работы:
;А - десятки тысяч,
;В - тысячи и сотни,
;С - десятки и единицы.
;BCD1B - программа перевода однобайтного
;числа в двоично-десятичный код.
;Двоичное число записывается
;в регистр Н, регистр L сбрасывается.
;результат работы:
;А - разряды сотен,
;В - разряды десятков и единиц.

BCD2B:    MVI Е,17     ;установка счетчика
                       ;первого цикла
          CALL CONV    ;вычисление младшего 
                       ;двоично-десятичного байта
          MOV С,А      ;вычисленный результат сохранен
          MVI Е,17     ;установка счетчика
                       ;второго цикла 
          JMP PROD
BCD1B:    MVI E,9      ;установка счетчика 
                       ;для программы BCD1B 
          CALL CONV    ;вычисление двух
                       ;старших байтов
          MOV В,А      ;запомнен промежуточный 
                       ;двоично-десятичный результат
          MOV A,L      ;установка старшего 
                       ;двоично-десятичного байта 
          RET 
CONV:     XRA А        ;сброс регистра А в нуль
SBIT:     DCR E        ;уменьшение на 1 
                       ;счетчика числа циклов 
          RZ
          DAD H        ;сдвиг старших разрядов 
                       ;в перенос 
          ADC A 
          DAA          ;двоично-десятичная коррекция
          JNC SBIT     ;двоично-десятичный 
                       ;байт больше 99?
          INX H        ;да 
          JMP SBIT

     Обратите внимание, как в строке с меткой CONV: устанавливается в нуль регистр А. Операция ИСКЛЮЧАЮЩЕЕ ИЛИ аккумулятора с самим собой обнулит его, а также сбросит и бит переноса.
     Приведенные программы полезны, если необходимо выводить на экран результаты вычислений. А как быть, если необходимо преобразовать однобайтное или двухбайтное десятичное число в двоичное? Это не сложно. Для этого надо выделить биты, определяющие десятки тысяч, и умножить их на 10000, затем выделить биты, определяющие тысячи, и умножить на 1000, выделить сотни и умножить на 100, выделить десятки и умножить на 10, и, наконец, выделить единицы. Сложение всех этих чисел даст нужный результат.
     Все эти действия выполняет следующая программа.

;вход в программу: 
;А - десятки тысяч, 
;В - тысячи и сотни,
;С - десятки и единицы.
;результат работы:
;HL - двоичное число.

DVH:     LXI D,10000
         CALL UMNOG
         PUSH H        ;обработаны десятки тысяч 
                       ;и сохранены в стеке 
         MOV А,В       ;разряды тысяч занимают 
                       ;четыре старших бита 
         RAR 
         RAR 
         RAR
         RAR           ;разряды тысяч в 
                       ;младших битах 
         ANI 0FH       ;выделены разряды тысяч
         LXI D,1000
         CALL UMNOG    ;обработаны разряды тысяч 
         POP D         ;DE - предыдущий результат 
         DAD D 
         PUSH H 
         MOV A,B 
         ANI 0FH       ;выделены разряды сотен
         LXI D,100 
         CALL UMNOG 
         POP D 
         DAD D 
         PUSH H 
         MOV A,C 
         RAR 
         RAR 
         RAR 
         RAR 
         ANI 0FH       ;выделены разряды десятков 
         LXI D,10 
         CALL UMNOG 
         POP D 
         DAD D 
         MOV A,C 
         ANI 0FH       ;выделены разряды единиц 
         MOV E,A 
         MVI D,0
         DAD D         ;HL - исходное число 
                       ;в двоичном виде 
         RET

     Заключение
     Разберитесь, как работают эти программы, поскольку изучение хорошо прокомментированных программ позволяет быстро научиться писать программы самим. И еще совет: если вы хотите всерьез заниматься вычислительной техникой, собирайте различные прикладные программы - математические вычисления, обработка данных и т.п. Это позволит вам со временем сформировать полезную библиотеку программ.


Hosted by uCoz