Разное

Модуль числа ассемблер: Ассемблерные модули

Содержание

Ассемблерные модули



Как создать перемещаемый код — исследуем вопрос

……….Содержание:

……….Введение

……….Создание перемещаемого модуля
………. — Исходные подпрограммы
………. — Начало модуля
………. — Переделка исходных подпрограмм
………. — Сборка модуля
………. — Настройка всех модулей проекта на один контроллер

……….Подключение перемещаемого ассемблерного модуля к проекту
……….Директива EXTERN. Задействуем модуль в основной программе
……….Подключаемый заголовочный файл
……….Блокировка повторного включения заголовочных файлов
……….Литература


Введение


……….Прежде всего, звучит вопрос: «Зачем всё это нужно?»
……….Отвечу на него в меру своего понимания. Когда вы только начинаете осваивать программирование на ассемблере для PIC микроконтроллеров и делаете свои первые проекты, модули вовсе не нужны, и вполне можно обходиться без них.

……….Если продолжаете программировать, и счёт вашим проектам идёт уже на десятки, то, возможно, вы начнёте замечать, что часто повторяете одни и те же действия со своим собственным кодом. То есть создаёте новый проект в MpLab, копируете в него пустой шаблон-заготовку для будущей программы, копируете в текст свои готовые программы и подпрограммы, а потом часть программы доделываете уже под конкретные задачи конкретного устройства. Чтобы избежать рутинных операций с копированием готового ассемблерного кода в новый проект, разработано несколько инструментов.

……….- Макроопределения (макросы)
……….- Перемещаемые модули
……….- Библиотеки подпрограмм
……….- Языки высокого уровня

Модули применяются для облегчения
ПОВТОРНОГО ИСПОЛЬЗОВАНИЯ КОДА


……….Разработчики MpLab, в частности — ассемблера Mpasm, позаботились о том, чтобы облегчить программистам труд и создали систему, пользуясь которой, возможно создавать библиотеки своих собственных программ и легко подключать их к новым проектам.

……….В этой статье будет рассмотрен способ оформления и использования модулей ассемблерного кода для микроконтроллеров Microchip среднего семейства.

Создание перемещаемого модуля

……….При создании единичного проекта переменные задаются в фиксированных регистрах при помощи директив equ и cblock, а программа и подпрограммы сразу же размещаются в фиксированных адресах при помощи директивы org.

……….При создании перемещаемого кода ситуация другая. Адреса для переменных и адреса размещения модулей кода назначаются автоматически в процессе компиляции проекта.

……….Это основное преимущество перемещаемого кода – он может располагаться в любых адресах и работать с регистрами в любых банках микроконтроллера (речь идёт о средней серии PIC16Fxxx, в которой присутствует страничная адресация ОЗУ).

……….Основное преимущество оборачивается и некоторой избыточностью. В перемещаемом коде нужно обеспечивать выбор нужного банка используемых регистров и учесть, что код может оказаться в любых страницах памяти программ. То есть нужно предустанавливать биты PR0, PR1, IRP регистра STATUS при работе с переменными и регистр PCLATH при вызове подпрограмм.

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

Исходные подпрограммы


……….Первая подпрограмма преобразует число в диапазоне 0…99 из двоичного кода в десятичный. Вторая делает обратное преобразование и из десятичного вида переводит число в двоичный код.

……….Подпрограммы сделаны для устройства с двухзначной динамической индикацией для ввода с клавиатуры и вывода на дисплей числа в диапазоне 0…99. Рассчитаны они на работу с нулевым банком регистров и в нулевой странице памяти программ.

……….Вот эти подпрограммы:


; двоичное число(0…99) в аккумуляторе в десятичное(e_rez/d_rez)
; Вход:
; в аккумуляторе преобразуемое число 0. ..99
; В программе определить ячейки e_rez d_rez
; — dd_preo
;===============================================================
dd_preo    movwf       e_rez         ; загружаем число в ячейку единиц
                                     ; делим число на 10 — получим десятки
d_10       clrf        d_rez
           movlw       0Ah   
           bcf         STATUS,C
d_10_cikl  subwf       e_rez,F       ; вычитаем из преобразуемого числа 10
           btfss       STATUS,C
           goto        dd_ed         ; перенос (результат отрицательный),
                                     ; прекращаем вычитание пререноса нет
           incf        d_rez,F       ; увеличиваем на 1 регистр десятков
           goto        d_10_cikl
dd_ed      addwf       e_rez,F       ; прибавив 10, получим единицы
           return

; Подпрограмма преобразования числа в двоичный формат
; из двух десятичных разрядов в диапазоне 0…99
; Вход:
; в регистре FSR адрес младшего (старший — следующий адрес)
; Выход
; в аккумуляторе — число в двоичном виде
; — decb_preo
;===============================================================
decb_preo  incf        FSR,F         ; адрес старшего
           movf        INDF,W
           movwf       temp          ; старший во временную ячейку — умножаем на 10
           bcf         STATUS,C
           rlf         temp,F

           rlf         temp,F
           rlf         temp,F        ; умножили на 8
           addwf       temp,F
           addwf       temp,F        ; умножили на 10
           decf        FSR,F         ; адрес младшего
           movf        INDF,W
           addwf       temp,W
           return
           end

. ………Наша задача сформировать из этих подпрограмм перемещаемый ассемблерный модуль. Учесть, что регистры, с которыми будут работать подпрограммы, могут оказаться в любых адресах и банках. Сам код подпрограмм также может быть размещён при компиляции в любых страницах памяти программ.
……….Чтобы сделать этот код перемещаемым, его придётся переделать и  дополнить.


Начало модуля

……….Необходимо определить однобайтные переменные  e_rez, d_rez, temp. Для этого воспользуемся директивой udata. Кроме того, чтобы основная программа могла получить доступ к переменным e_rez, d_rez, их необходимо сделать глобальными, то есть применить к ним директиву global.

……….Итак, начало нашего будущего модуля:

           global      e_rez, d_rez
           udata
d_rez      res         1
e_rez      res         1
temp       res         1

. ………Директива udata объявляет (говорит ассемблеру о начале) секцию переменных. Директива res резервирует место под переменные, то есть транслятор (ассемблер) выделяет столько байт, сколько указано.
……….В нашем случае мы объявили три переменные e_rez, d_rez, temp, под каждую из которых будет выделен один байт памяти.

……….Ассемблер Mpasm может быть использован двумя способами:

……….-   для генерации абсолютного кода, который может быть напрямую исполнен микроконтроллером

……….- для генерации перемещаемого кода, который может быть объединён с другими отдельно скомпилированными файлами

……….Мы задействуем его во втором варианте, для объединения нескольких файлов в один проект.

……….Когда файлов в проекте больше одного, то в дело включается линкер. Ассемблер генерирует из каждого АСМ файла объектный файл. Линкер собирает отдельные объектные файлы в цельный проект, пересчитывает адреса размещения кода и адреса меток в коде, а также размещает переменные в RAM области с назначением им конкретных адресов. ……….Почему модуль кода называется перемещаемым?
……….Он может быть размещён линкером в любых адресах памяти программ и работать с регистрами в любых адресах памяти данных микроконтроллера.

……….В объектном файле находится готовый код и информация об используемых данных. Адрес начала этого кода в будущем проекте можем определить заранее или оставить его определение на усмотрение линкера, что обычно и делается. В некоторых случаях необходимо зафиксировать размещение кода.

……….Директива code объявляет начало секции кода и позволяет при необходимости зафиксировать секцию кода в конкретных адресах памяти программ микроконтроллера.

……….Наращиваем «шапку» нашего перемещаемого модуля.

           global      e_rez, d_rez
           udata
e_rez      res         1
d_rez      res         1
temp       res         1

           code


. ………Если бы мы хотели разместить начало кода в определённых адресах памяти, например с адреса 0x0000, то пришлось бы сделать запись:

           code        0x0000

……….Применяется фиксация адреса в перемещаемом коде в редких случаях. Когда необходимо указать на начало программы, при объявлении начала адреса программы прерывания, размещении загрузчика или таблицы с данными. Фиксирование адреса в перемещаемом коде в других случаях практически не применяется, так как фиксированные адреса могут привести к несовместимости модулей.

……….Каждую секцию кода можно назвать отдельным именем. Впоследствии, если будет необходимость включить подпрограммы в библиотечный файл, это пригодится. Так и сделаем:

           global      e_rez, d_rez
           udata
e_rez      res         1
d_rez      res         1
temp       res         1

bin99dec_seg   code


. ………Именование секций, подпрограмм, переменных и других элементов при программировании с возможностью повторного использования кода – отдельная тема. Имя подпрограммы должно отражать её функциональное назначение и способствовать тому, чтобы, всего лишь взглянув на имя подпрограммы, модуля или файла, можно было легко вспомнить и понять функциональное назначение кода. Подробнее с правилами оформления кода и именования меток можно ознакомиться в статье: «MPASM. Как правильно оформлять программы на ассемблере для PIC-контроллеров»

Переделка исходных подпрограмм

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

. ………Банк 0 — адреса — 0x000…0x07F
……….Банк 1 — адреса — 0x080…0x0FF
……….Банк 2 — адреса — 0x100…0x17F
……….Банк 3 — адреса — 0x180…0x1FF

……….Предустанавливать биты выбора банка для каждой из переменных, объявленных в одной секции udata не требуется. Достаточно выбрать банк единожды для одной секции. Линкер размещает переменные из одной секции в одном и том же банке.

……….Работая с регистрами INDF и FSR при использовании косвенной адресации в перемещаемом коде, необходимо определить бит IRP регистра STATUS.  В микроконтроллерах PIC16Fxxx два банка косвенной адресации. Нулевой банк 0x000…0x0FF и первый банк 0x100…0x1FF. Бит IRP регистра STATUS определяет, к какому именно банку регистров мы обращаемся. Для выбора банка косвенной адресации в перемещаемом коде служит директива bankisel.


bin99dec_seg code

;===============================================================
; — Bin99Dec
; пробразование двоичного числа в десятичное
; Параметры:
;   w — двоичное число(0. ..99)
; Результат:
;   e_rez — единицы
;   d_rez — десятки
;===============================================================

Bin99Dec   
           banksel     e_rez         ; выставляем биты RP0,RP1 регистра STATUS для выбора банка
           movwf       e_rez

d_10       clrf        d_rez
           movlw       0Ah
           bcf         STATUS,C

d_10_loop  subwf       e_rez,F       ; делим число на 10 — получим десятки
           btfss       STATUS,C
           goto        dd_ed         ; перенос (результат отрицательный),
                                     ; прекращаем вычитание

           incf        d_rez,F       ; увеличиваем десятки
           goto        d_10_loop

dd_ed      addwf       e_rez,F       ; прибавив 10, получим единицы
           return
;————————————

dec99bin_seg code

;===============================================================
; — Dec99Bin
; преобразование десятичного числа в двоичное
; Вход:
; в регистре FSR адрес младшего(старший — следующий адрес)
; (бит IRP – номер банка косвенной адресации)
; Результат:
;   W — число в двоичном виде
;===============================================================

Dec99Bin
           incf        FSR,F         ; адрес старшего
           movf        INDF,W

           banksel     temp
           movwf       temp          ; старший во временную ячейку

           bcf         STATUS,C
           rlf         temp,F
           rlf         temp,F
           addwf       temp,F
           rlf         temp,F        ; умножили на 10

           decf        FSR,F
           movf        INDF,W
           addwf       temp,W        ; прибавили младший
           return
;————————————


. ………Постоянное применение директив banksel и bankisel создаёт ту самую избыточность перемещаемого кода, которой обычно удаётся избежать при создании кода абсолютного. Перемещаемый код требует несколько больше места в памяти программ контроллера. Это относится в основном к микроконтроллерам средней серии типа PIC16Fxxx. В 18-й серии и более новых микроконтроллерах  Microchip большей разрядности ОЗУ устроено по–другому, и перемещаемый код более компактен.

Сборка модуля

……….Следующий необходимый шаг – объявить подпрограммы Bin99Dec, Dec99Bin глобальными, чтобы основная программа могла их вызвать. Что происходит при объявлении метки глобальной, вы наверное уже догадались. Ассемблер в объектном файле создаёт таблицу меток, к которым разрешён доступ извне. Если основная программа обращается к глобальной метке внешнего модуля, то всё отлично, доступ разрешён. Если же метка глобальной не является, то доступа к ней нет. При попытке обращения к внутренней метке модуля ассемблер выдаст ошибку, что идентификатор неопределен.
……….Это позволяет использовать одинаковые имена меток в разных модулях одного проекта и обеспечивает разделение регистров между модулями. Ячейки, которые глобальными не являются, используются только внутри модуля и к ним нет доступа из других модулей программы………..Для окончательной сборки модуля остаётся добавить в него строку подключения файла определений для микроконтроллера среднего семейства и завершить всё директивой end

           include   <p16F628a.inc>  ;подключили файл определений

           global      e_rez, d_rez
           global      Bin99Dec, Dec99Bin

;=================
; Секция данных
;=================

           udata

e_rez      res         1             ; единицы
d_rez      res         1             ; десятки

temp       res         1

;==============
; Секция кода
;==============

bin99dec_seg code

;===============================================================
; — Bin99Dec
; пробразование двоичного числа в десятичное
; Параметры:
;   w — двоичное число(0. ..99)
; Результат:
;   e_rez — единицы
;   d_rez — десятки
;===============================================================

Bin99Dec   
           banksel     e_rez         ; выставляем биты RP0,RP1 регистра STATUS
                                     ; для выбора банка
           movwf       e_rez

d_10       clrf        d_rez
           movlw       0Ah
           bcf         STATUS,C

d_10_loop  subwf       e_rez,F       ; делим число на 10 — получим десятки
           btfss       STATUS,C
           goto        dd_ed         ; перенос (результат отрицательный),
                                     ; прекращаем вычитание

           incf        d_rez,F       ; увеличиваем десятки
           goto        d_10_loop

dd_ed      addwf       e_rez,F       ; прибавив 10 получим единицы
           return
;————————————

dec99bin_seg code

;===============================================================
; — Dec99Bin
; преобразование десятичного числа в двоичное
; Вход:
; в регистре FSR адрес младшего(старший — следующий адрес)
; (бит IRP – номер банка косвенной адресации)
; Результат:
;   W — число в двоичном виде
;===============================================================

Dec99Bin
           incf        FSR,F         ; адрес старшего
           movf        INDF,W

           banksel     temp
           movwf       temp          ; старший во временную ячейку

           bcf         STATUS,C
           rlf         temp,F
           rlf         temp,F
           addwf       temp,F
           rlf         temp,F        ; умножили на 10

           decf        FSR,F
           movf        INDF,W
           addwf       temp,W        ; прибавили младший
           return
;————————————

           end


Настройка всех модулей проекта

на один контроллер

. ………Если модулей в проекте несколько, то придётся настроить их все на один и тот же тип микроконтроллера. Можно для этого во всех модулях переделать строку:

           include    <p16F628a.inc>
……….Чтобы не исправлять эту строку во  всех готовых модулях, входящих в проект, вместо неё включаем файл настроек для всех модулей проекта:

           include    <hardware_profile.inc>
……….Создаём файл  “hardware_profile.inc” и прописываем в нём строки, которые окажутся включенными во все модули проекта:

           list        p=16f628a
           include     <p16F628a.inc>
. ………Впоследствии, внеся изменения в этот файл, можно внести изменения и перенастроить проект на другой микроконтроллер, не изменяя код в файлах модулей.
……….Файл модуля примет вид:

           #include     <hardware_profile.inc> ; настройка

           global      e_rez, d_rez
           global      Bin99Dec, Dec99Bin

;=================
; Секция данных
;=================

           udata

e_rez      res         1             ; единицы
d_rez      res         1             ; десятки

temp       res         1

;==============
; Секция кода
;==============

bin99dec_seg code

;===============================================================
; — Bin99Dec
; пробразование двоичного числа в десятичное
; Параметры:
;   w — двоичное число(0…99)
; Результат:
;   e_rez — единицы
;   d_rez — десятки
;===============================================================

Bin99Dec   
           banksel     e_rez         ; выставляем биты RP0,RP1 регистра STATUS для выбора банка
           movwf       e_rez

d_10       clrf        d_rez
           movlw       0Ah
           bcf         STATUS,C

d_10_loop  subwf       e_rez,F       ; делим число на 10 — получим десятки
           btfss       STATUS,C
           goto        dd_ed         ; перенос (результат отрицательный), прекращаем вычитание

           incf        d_rez,F       ; увеличиваем десятки
           goto        d_10_loop

dd_ed      addwf       e_rez,F       ; прибавив 10 получим единицы
           return
;————————————

dec99bin_seg code

;===============================================================
; — Dec99Bin
; преобразование десятичного числа в двоичное
; Вход:
; в регистре FSR адрес младшего(старший — следующий адрес)
; (бит IRP – номер банка косвенной адресации)
; Результат:
;   W — число в двоичном виде
;===============================================================

Dec99Bin
           incf        FSR,F         ; адрес старшего
           movf        INDF,W

           banksel     temp
           movwf       temp          ; старший во временную ячейку

           bcf         STATUS,C
           rlf         temp,F
           rlf         temp,F
           addwf       temp,F
           rlf         temp,F        ; умножили на 10

           decf        FSR,F
           movf        INDF,W
           addwf       temp,W        ; прибавили младший
           return
;————————————

           end



Подключение перемещаемого ассемблерного

модуля к проекту

. ………Так как речь идёт о применении в проекте нескольких файлов, то нужно создать ещё один файл – основной файл проекта. Создадим простейшую «пустышку». Для понимания того, как задействовать модули, этого достаточно. Вот код основного файла проекта:

;========================
;  Подключаемые файлы
;========================
           #include     <hardware_profile.inc> ; настройка

; =====Конфигурация=========
           __CONFIG    _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF & _BODEN_OFF & _MCLRE_OFF

;=================================
; Секция основного кода программы
;=================================

reset_seg  code        0x0000
reset      lgoto       start

int_seg    code        0x0004
           nop
           return

start_seg  code    
start      nop

;==============================
; Главный цикл программы
; — gl_cikl
;==============================
gl_cikl    nop
           goto        gl_cikl

           end

. ………Сохраняем этот код в файл с именем «mod_gl.asm».
……….Создаём для проекта новую папку и размещаем в неё подготовленные файлы. При сборке и компиляции проекта задействуется линкер, поэтому в папку проекта копируем файл скрипта линкера для микроконтроллера PIC16F628A «16f628a.lkr».

……….Воспользовавшись Project Wizard, создаем новый проект. Первоначально у нас задействовано четыре файла, и окно проекта выглядит так:


……….Жмём кнопку «Build All». Всё компилируется. Проверим, что получилось в памяти программ.

  Line Address Opcode  Label    Disassembly              

     1   000     2821 reset     GOTO start   
     2   001     3400           RETLW 0      
     3   002     3400           RETLW 0      
     4   003     3FFF                        
     5   004     0000           NOP          
     6   005     0008           RETURN       
     7   006     0A84 Dec99Bin  INCF FSR, F  
     8   007     0800           MOVF INDF, W
     9   008     1283           BCF STATUS, 0x5
    10   009     1703           BSF STATUS, 0x6
    11   00A     00A2           MOVWF 0x22   
    12   00B     1003           BCF STATUS, 0
    13   00C     0DA2           RLF 0x22, F  
    14   00D     0DA2           RLF 0x22, F  
    15   00E     07A2           ADDWF 0x22, F
    16   00F     0DA2           RLF 0x22, F  
    17   010     0384           DECF FSR, F  
    18   011     0800           MOVF INDF, W
    19   012     0722           ADDWF 0x22, W
    20   013     0008           RETURN       
    21   014     1283 Bin99Dec  BCF STATUS, 0x5
    22   015     1703           BSF STATUS, 0x6
    23   016     00A0           MOVWF 0x20   
    24   017     01A1 d_10      CLRF 0x21    
    25   018     300A           MOVLW 0xa    
    26   019     1003           BCF STATUS, 0
    27   01A     02A0 d_10_loop SUBWF 0x20, F
    28   01B     1C03           BTFSS STATUS, 0
    29   01C     281F           GOTO dd_ed   
    30   01D     0AA1           INCF 0x21, F
    31   01E     281A           GOTO d_10_loop
    32   01F     07A0 dd_ed     ADDWF 0x20, F
    33   020     0008           RETURN       
    34   021     0000 start     NOP          
    35   022     0000 gl_cikl   NOP          
    36   023     2822           GOTO gl_cikl

. ………Сразу видим, что секции кода (подпрограммы Bin99Dec,Dec99Bin и основная программа)  поменялись местами. На будущее нужно учесть, что при сборке проекта отдельные секции кода могут быть размещены линкером в любых адресах. Ну, да на то они и перемещаемые.

……….Если заглянуть в файл регистров проекта (в символьном виде), то ячейки e_rez, d_rez, temp  обнаружим в адресах 0x120, 0x121, 0x122, то есть во втором банке ОЗУ.



Директива EXTERN

Задействуем модуль в основной программе

……….Для того чтобы основной файл смог использовать внешние метки необходимо добавить в него строку:

           extern      e_rez, d_rez, Bin99Dec, Dec99Bin

……….Директива extern даёт понять ассемблеру, что метки, указанные за ней, внешние и находятся в других файлах проекта. Линкеру предстоит найти их при компиляции в других объектных файлах и добавить в таблицу используемых меток основного файла.

……….В первом примере подпрограммы модуля не вызываются, и обращения к ячейкам  e_rez, d_rez  из основной программы нет. Добавим несколько обращений к программам модуля,  усложним немного основную программу.

;========================
;  Подключаемые файлы
;========================
           #include     <hardware_profile.inc> ; настройка

;————————

           extern      e_rez, d_rez, Bin99Dec, Dec99Bin

; =====Конфигурация=========
           __CONFIG    _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF & _BODEN_OFF & _MCLRE_OFF

;=================================
; Секция основного кода программы
;=================================

reset_seg  code        0x0000
reset      lgoto       start

int_seg    code        0x0004
           nop
           return

start_seg  code    
start      nop
           movlw       . 32
           lcall       Bin99Dec      ; преобразуем число 32 в десятичный вид
           pagesel     $

           bankisel    e_rez         ; выбор банка косвенной адресации — бит IRP
                                     ; регистра STATUS
           movlw       e_rez
           movwf       FSR

           banksel     e_rez         ; выставляем биты RP0,RP1 регистра STATUS
                                     ; для выбора банка
           movlw       .7
           movwf       e_rez
           movlw       .5
           movwf       d_rez         ; загрузили число 57

           lcall       Dec99Bin      ; преобразуем число в e_rez, d_rez в двоичный вид
           pagesel     $

;==============================
; Главный цикл программы
; — gl_cikl
;==============================
gl_cikl    nop
           goto        gl_cikl

           end


. ………Так как модуль может оказаться в любой странице памяти программ, при вызове подпрограмм используется встроенный макрос lcall. Макрос lcall перед вызовом подпрограммы настраивает соответствующие биты регистра PCLATH на ту страницу памяти программ, где расположена вызываемая подпрограмма.

……….При возврате из подпрограммы регистр PCLATH восстанавливается макрокомандой pagesel и настраивает биты PCLATH в соответствие с текущей страницей памяти программ.

           pagesel     $

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

           extern      e_rez, d_rez, Bin99Dec, Dec99Bin

……….Допустим мы собрали несколько таких модулей, в каждом решили конкретные задачи и разместили по несколько подпрограмм, каждая из которых работает со своими переменными и решает определённую задачу. Например, в одном модуле все подпрограммы, обеспечивающие связь по USART, в другом решается задача измерения температуры с датчика DS18B20, в третьем — подпрограммы работы с внешней памятью, типа 24Cxx, и т.д.

……….Для каждого из модулей придётся добавить в основной файл проекта строки с определением внешних меток директивой extern.

Подключаемый заголовочный файл

……….Основной способ, применяемый при подключении модуля к проекту, – использование заголовочного файла.
……….Создаём ещё один файл с названием «bin99dec.inc». В этом файле прописываем:

; bin99dec. inc – заголовочный файл к модулю
; bin99dec.asm – подпрограммы математических преобразований

; Переменные
         extern      d_rez, e_rez ; ячейки для хранения десятичного числа в диапазоне 0…99

; Подпрограммы
         extern      Bin99Dec  ; число в аккумуляторе в десятичный вид,
                               ; результат в d_rez, e_rez
         extern      Dec99Bin  ; десятичное 0…99 в двоичный вид, результат в аккумуляторе
                               ; вход: в FSR адрес младшего (старший — следующий адрес)


……….В файле фактически дублируется строка:

           extern      e_rez, d_rez, Bin99Dec, Dec99Bin

……….Комментарии позволят разобраться в функциональном назначении модуля, не заглядывая в код самого модуля,  только лишь заглянув в заголовочный файл. Кроме того, в заголовочный файл можно включить макроопределения (макросы) и константы, необходимые для работы с модулем.
……….Создав файл «bin99dec.inc», подключаем его к основному проекту при помощи директивы include.
……….Основной файл проекта в этом случае будет выглядеть так:

;========================
;  Подключаемые файлы
;========================
           #include     <hardware_profile.inc> ; настройка
           #include     <bin99dec.inc> ; заголовок к модулю bin_dec преобразований

; =====Конфигурация=========
           __CONFIG    _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF & _BODEN_OFF & _MCLRE_OFF

;=================================
; Секция основного кода программы
;=================================

reset_seg  code        0x0000
reset      lgoto       start

int_seg    code        0x0004
           nop
           return

start_seg  code    
start      nop
           movlw       . 32
           lcall       Bin99Dec      ; преобразуем число 32 в десятичный вид
           pagesel     $

           bankisel    e_rez         ; выбор банка косвенной адресации — бит IRP
                                     ; регистра STATUS
           movlw       e_rez
           movwf       FSR

           banksel     e_rez         ; выставляем биты RP0,RP1 регистра STATUS
                                     ; для выбора банка
           movlw       .7
           movwf       e_rez
           movlw       .5
           movwf       d_rez         ; загрузили число 57

           lcall       Dec99Bin      ; преобразуем число в e_rez, d_rez в двоичный вид
           pagesel     $

;==============================
; Главный цикл программы
; — gl_cikl
;==============================
gl_cikl    nop
           goto        gl_cikl

           end


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

           extern      e_rez, d_rez, Bin99Dec, Dec99Bin

……….Директива include работает по тому же принципу, что и макрос, но в приложении к целому файлу, являясь удобным способом подстановки готового кода всего лишь одной строкой.
……….В окно основного проекта можно добавить файл заголовка, в пункт «Header Files», чтобы можно было одним кликом заглянуть в него при необходимости:


Блокировка повторного включения

заголовочных файлов

……….Когда модули становятся основным способом программирования, могут возникнуть довольно сложные ситуации, когда один модуль использует подпрограммы другого модуля. Возможно включение в заголовочный файл одного модуля заголовочного файла другого модуля и повтор включенных заголовков. Если произойдёт дублированное включение одного и того же заголовка, то неизбежна ошибка при компиляции:
……….«Дублирование меток». ……….Чтобы этого избежать, применяется блокировка повторного включения файла заголовка в один и тот же файл. Для блокировки повторного включения применяются директивы условной компиляции:

           #ifndef    BIN99DEC_H     ; Блокируем повторное включение заголовка
           #define    BIN99DEC_H

; Здесь размещается код заголовка

           #endif


……….С помощью этих директив исключается повторное включение заголовка в один  тот же файл проекта. Заголовочный файл в нашем примере примет такой вид:

           #ifndef    BIN99DEC_H     ; Блокируем повторное включение заголовка
           #define    BIN99DEC_H

; bin99dec. inc – заголовочный файл к модулю
; bin99dec.asm – подпрограммы математических преобразований

; Переменные

           extern      d_rez, e_rez  ; ячейки для хранения десятичного числа в диапазоне 0…99

; Подпрограммы

           extern      Bin99Dec      ; число в аккумуляторе в десятичный вид,
                                     ; результат в d_rez, e_rez
           extern      Dec99Bin      ; десятичное 0…99 в двоичный вид, результат в аккумуляторе
                                     ; вход: в FSR адрес младшего (старший — следующий адрес)

           #endif


……….Вот и весь принцип построения модулей и подключения их к проектам. Создавать модули несколько сложнее, чем единичный проект. Но выигрыш от такого подхода хорошо осознаётся со временем, когда программ и проектов становится много, и что-то найти в собственных исходниках иногда сложнее, чем переписать весь код по-новой. Готовая собственная библиотека модулей — отличное подспорье, если вы много программируете.

……….Литература:

……….1. MPASM. Как правильно оформлять программы на ассемблере для PIC-контроллеров (пособие для начинающих)
……….2. Как оформлять модули
……….3. MPASM. Руководство пользователя



Учебный курс. Часть 22. Вывод чисел на консоль

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

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

Для начала рассмотрим две полезные процедуры, которые будут использоваться в дальнейшем. Чтобы постоянно не обращаться в коде в функции DOS 09h, удобно написать маленькую процедуру для вывода строки:

;Процедура вывода строки на консоль
; DI - адрес строки
print_str:
    push ax
    mov ah,9                ;Функция DOS 09h - вывод строки
    xchg dx,di              ;Обмен значениями DX и DI
    int 21h                 ;Обращение к функции DOS
    xchg dx,di              ;Обмен значениями DX и DI
    pop ax
    ret

;Процедура вывода строки на консоль ; DI — адрес строки print_str: push ax mov ah,9 ;Функция DOS 09h — вывод строки xchg dx,di ;Обмен значениями DX и DI int 21h ;Обращение к функции DOS xchg dx,di ;Обмен значениями DX и DI pop ax ret

В качестве параметра ей передаётся адрес строки в регистре DI. Строка должна оканчиваться символом ‘$’. Здесь используется команда XCHG, которая выполняет обмен значениями двух операндов.

Вторая полезная процедура – вывод конца строки. Она вызывает первую процедуру для вывода двух символов CR(13) и LF(10). Вызывается без параметров и не изменяет регистры.

;Процедура вывода конца строки (CR+LF)
print_endline:
    push di
    mov di,endline          ;DI = адрес строки с символами CR,LF
    call print_str          ;Вывод строки на консоль
    pop di
    ret
...
endline db 13,10,'$'

;Процедура вывода конца строки (CR+LF) print_endline: push di mov di,endline ;DI = адрес строки с символами CR,LF call print_str ;Вывод строки на консоль pop di ret … endline db 13,10,’$’

Вывод чисел в двоичном виде

Алгоритм вывода в двоичном виде очень прост. Нужно проанализировать все биты числа и поместить в строку символы ‘0’ или ‘1’ в зависимости от значения соответствующего бита. Удобно делать это с помощью циклического сдвига в цикле. Сдвинутый бит оказывается в флаге CF, а после завершения цикла в регистре то же значение, что и в начале. Процедура byte_to_bin_str преобразует байт в регистре AL в строку. Адрес буфера для строки передаётся в регистре DI. Процедура всегда записывает в буфер 8 символов, так как в байте 8 бит.

;Процедура преобразования байта в строку в двоичном виде
; AL - байт.
; DI - буфер для строки (8 символов). Значение регистра не сохраняется.
byte_to_bin_str:
    push cx                 ;Сохранение CX
    mov cx,8                ;Счётчик цикла
 
btbs_lp:
    rol al,1                ;Циклический сдвиг AL влево на 1 бит
    jc btbs_1               ;Если выдвинутый бит = 1, то переход
    mov byte[di],'0'        ;Добавление символа '0' в строку
    jmp btbs_end
btbs_1:
    mov byte[di],'1'        ;Добавление символа '1' в строку
btbs_end:
    inc di                  ;Инкремент DI
    loop btbs_lp            ;Команда цикла
 
    pop cx                  ;Восстановление CX
    ret                     ;Возврат из процедуры

;Процедура преобразования байта в строку в двоичном виде ; AL — байт. ; DI — буфер для строки (8 символов). Значение регистра не сохраняется. byte_to_bin_str: push cx ;Сохранение CX mov cx,8 ;Счётчик цикла btbs_lp: rol al,1 ;Циклический сдвиг AL влево на 1 бит jc btbs_1 ;Если выдвинутый бит = 1, то переход mov byte[di],’0′ ;Добавление символа ‘0’ в строку jmp btbs_end btbs_1: mov byte[di],’1′ ;Добавление символа ‘1’ в строку btbs_end: inc di ;Инкремент DI loop btbs_lp ;Команда цикла pop cx ;Восстановление CX ret ;Возврат из процедуры

Используя эту процедуру, легко написать ещё одну для вывода слова в двоичном виде:

;Процедура преобразования слова в строку в двоичном виде
; AX - слово
; DI - буфер для строки (16 символов). Значение регистра не сохраняется. 
word_to_bin_str:
    xchg ah,al              ;Обмен AH и AL
    call byte_to_bin_str    ;Преобразование старшего байта в строку
    xchg ah,al              ;Обмен AH и AL
    call byte_to_bin_str    ;Преобразование младшего байта в строку
    ret

;Процедура преобразования слова в строку в двоичном виде ; AX — слово ; DI — буфер для строки (16 символов). Значение регистра не сохраняется. word_to_bin_str: xchg ah,al ;Обмен AH и AL call byte_to_bin_str ;Преобразование старшего байта в строку xchg ah,al ;Обмен AH и AL call byte_to_bin_str ;Преобразование младшего байта в строку ret

И наконец вот две процедуры, которые делают то, что нужно 🙂 Буфер имеет размер 17 символов, так как в слове 16 бит + символ ‘$’, обозначающий конец строки.

;Процедура вывода байта на консоль в двоичном виде
; AL - байт
print_byte_bin:
    push di
    mov di,buffer           ;DI = адрес буфера
    call byte_to_bin_str    ;Преобразование байта в AL в строку
    mov byte[di],'$'        ;Добавление символа конца строки
    sub di,8                ;DI = адрес начала строки
    call print_str          ;Вывод строки на консоль
    pop di
    ret
 
;Процедура вывода слова на консоль в двоичном виде
; AX - слово
print_word_bin:
    push di
    mov di,buffer           ;DI = адрес буфера
    call word_to_bin_str    ;Преобразование слова в AX в строку
    mov byte[di],'$'        ;Добавление символа конца строки
    sub di,16               ;DI = адрес начала строки
    call print_str          ;Вывод строки на консоль
    pop di
    ret
. ..
buffer  rb 17

;Процедура вывода байта на консоль в двоичном виде ; AL — байт print_byte_bin: push di mov di,buffer ;DI = адрес буфера call byte_to_bin_str ;Преобразование байта в AL в строку mov byte[di],’$’ ;Добавление символа конца строки sub di,8 ;DI = адрес начала строки call print_str ;Вывод строки на консоль pop di ret ;Процедура вывода слова на консоль в двоичном виде ; AX — слово print_word_bin: push di mov di,buffer ;DI = адрес буфера call word_to_bin_str ;Преобразование слова в AX в строку mov byte[di],’$’ ;Добавление символа конца строки sub di,16 ;DI = адрес начала строки call print_str ;Вывод строки на консоль pop di ret … buffer rb 17

Полный исходный код примера вы можете скачать отсюда: printbin. asm. Результат работы программы выглядит вот так:

Вывод чисел в шестнадцатеричном виде

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

;Процедура преобразования числа (0-15) в шестнадцатеричную цифру
; вход : AL - число (0-15)
; выход: AL - шестнадцатеричная цифра ('0'-'F')
to_hex_digit:
    add al,'0'              ;Прибавляем символ '0' (код 0x30)
    cmp al,'9'              ;Сравнение с символом '9' (код 0x39)
    jle thd_end             ;Если получилось '0'-'9', то выход
    add al,7                ;Прибавляем ещё 7 для символов 'A'-'F'
thd_end:
    ret

;Процедура преобразования числа (0-15) в шестнадцатеричную цифру ; вход : AL — число (0-15) ; выход: AL — шестнадцатеричная цифра (‘0’-‘F’) to_hex_digit: add al,’0′ ;Прибавляем символ ‘0’ (код 0x30) cmp al,’9′ ;Сравнение с символом ‘9’ (код 0x39) jle thd_end ;Если получилось ‘0’-‘9’, то выход add al,7 ;Прибавляем ещё 7 для символов ‘A’-‘F’ thd_end: ret

Если значение тетрады от 0 до 9, то достаточно только прибавить код символа ‘0’ (0x30). А если значение больше 9, то надо прибавить ещё 7, чтобы получилась буква ‘A’-‘F’.

Теперь легко можно преобразовать байт в шестнадцатеричную строку, достаточно каждую из его тетрад заменить соответствующей цифрой:

;Процедура преобразования байта в строку в шестнадцатеричном виде
; AL - байт.
; DI - буфер для строки (2 символа). Значение регистра не сохраняется.
byte_to_hex_str:
    push ax
    mov ah,al               ;Сохранение значения AL в AH
    shr al,4                ;Выделение старшей тетрады
    call to_hex_digit       ;Преобразование в шестнадцатеричную цифру
    mov [di],al             ;Добавление символа в строку
    inc di                  ;Инкремент DI
    mov al,ah               ;Восстановление AL
    and al,0Fh              ;Выделение младшей тетрады
    call to_hex_digit       ;Преобразование в шестнадцатеричную цифру
    mov [di],al             ;Добавление символа в строку
    inc di                  ;Инкремент DI
    pop ax
    ret

;Процедура преобразования байта в строку в шестнадцатеричном виде ; AL — байт. ; DI — буфер для строки (2 символа). Значение регистра не сохраняется. byte_to_hex_str: push ax mov ah,al ;Сохранение значения AL в AH shr al,4 ;Выделение старшей тетрады call to_hex_digit ;Преобразование в шестнадцатеричную цифру mov [di],al ;Добавление символа в строку inc di ;Инкремент DI mov al,ah ;Восстановление AL and al,0Fh ;Выделение младшей тетрады call to_hex_digit ;Преобразование в шестнадцатеричную цифру mov [di],al ;Добавление символа в строку inc di ;Инкремент DI pop ax ret

Преобразование слова также не представляет трудности – сначала преобразуем старший байт, затем младший:

;Процедура преобразования слова в строку в шестнадцатеричном виде
; AX - слово
; DI - буфер для строки (4 символа). Значение регистра не сохраняется. 
word_to_hex_str:
    xchg ah,al              ;Обмен AH и AL
    call byte_to_hex_str    ;Преобразование старшего байта в строку
    xchg ah,al              ;Обмен AH и AL
    call byte_to_hex_str    ;Преобразование младшего байта в строку
    ret

;Процедура преобразования слова в строку в шестнадцатеричном виде ; AX — слово ; DI — буфер для строки (4 символа). Значение регистра не сохраняется. word_to_hex_str: xchg ah,al ;Обмен AH и AL call byte_to_hex_str ;Преобразование старшего байта в строку xchg ah,al ;Обмен AH и AL call byte_to_hex_str ;Преобразование младшего байта в строку ret

Полный исходный код примера: printhex.asm. Результат работы программы выглядит вот так:

Вывод чисел в десятичном виде

С десятичными числами немного сложнее. Для начала займёмся числами без знака. Чтобы преобразовать число в десятичную строку необходимо в цикле делить его на 10 (это основание системы счисления). Остатки от деления дают нам значения десятичных цифр. Первый остаток – младшая цифра, последний – старшая. Деление продолжается пока частное не равно нулю.

Например, если есть число 125. Делим его на десять: получаем 12, 5 в остатке. Потом делим 12 на десять: получаем 1, 2 в остатке. Наконец, 1 делим на 10: получаем 0, 1 в остатке. Цифры числа, начиная с младшей: 5, 2, 1. Так как обычно десятичные числа пишут, начиная со старшей цифры, то необходимо переставить их наоборот 🙂 Я для этого использовал стек.

В первом цикле производится деление, полученные остатки преобразуются в цифры и помещаются в стек. Во втором цикле символы извлекаются из стека (в обратном порядке) и помещаются в строку. Так как максимальное значение слова без знака 65536 (5 цифр), то в буфер записывается максимум 5 символов.

;Процедура преобразования слова в строку в десятичном виде (без знака)
; AX - слово
; DI - буфер для строки (5 символов). Значение регистра не сохраняется.
word_to_udec_str:
    push ax
    push cx
    push dx
    push bx
    xor cx,cx               ;Обнуление CX
    mov bx,10               ;В BX делитель (10 для десятичной системы)
 
wtuds_lp1:                  ;Цикл получения остатков от деления
    xor dx,dx               ;Обнуление старшей части двойного слова
    div bx                  ;Деление AX=(DX:AX)/BX, остаток в DX
    add dl,'0'              ;Преобразование остатка в код символа
    push dx                 ;Сохранение в стеке
    inc cx                  ;Увеличение счетчика символов
    test ax,ax              ;Проверка AX
    jnz wtuds_lp1           ;Переход к началу цикла, если частное не 0. 
 
wtuds_lp2:                  ;Цикл извлечения символов из стека
    pop dx                  ;Восстановление символа из стека
    mov [di],dl             ;Сохранение символа в буфере
    inc di                  ;Инкремент адреса буфера
    loop wtuds_lp2          ;Команда цикла
 
    pop bx
    pop dx
    pop cx
    pop ax
    ret

;Процедура преобразования слова в строку в десятичном виде (без знака) ; AX — слово ; DI — буфер для строки (5 символов). Значение регистра не сохраняется. word_to_udec_str: push ax push cx push dx push bx xor cx,cx ;Обнуление CX mov bx,10 ;В BX делитель (10 для десятичной системы) wtuds_lp1: ;Цикл получения остатков от деления xor dx,dx ;Обнуление старшей части двойного слова div bx ;Деление AX=(DX:AX)/BX, остаток в DX add dl,’0′ ;Преобразование остатка в код символа push dx ;Сохранение в стеке inc cx ;Увеличение счетчика символов test ax,ax ;Проверка AX jnz wtuds_lp1 ;Переход к началу цикла, если частное не 0. wtuds_lp2: ;Цикл извлечения символов из стека pop dx ;Восстановление символа из стека mov [di],dl ;Сохранение символа в буфере inc di ;Инкремент адреса буфера loop wtuds_lp2 ;Команда цикла pop bx pop dx pop cx pop ax ret

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

;Процедура преобразования байта в строку в десятичном виде (без знака)
; AL - байт.
; DI - буфер для строки (3 символа). Значение регистра не сохраняется.
byte_to_udec_str:
    push ax
    xor ah,ah               ;Преобразование байта в слово (без знака)
    call word_to_udec_str   ;Вызов процедуры для слова без знака
    pop ax
    ret

;Процедура преобразования байта в строку в десятичном виде (без знака) ; AL — байт. ; DI — буфер для строки (3 символа). Значение регистра не сохраняется. byte_to_udec_str: push ax xor ah,ah ;Преобразование байта в слово (без знака) call word_to_udec_str ;Вызов процедуры для слова без знака pop ax ret

Теперь разберёмся с числами со знаком. Сначала нужно проверить старший бит числа. Если число положительное, то его можно преобразовать также как число без знака. Если число отрицательное, то добавляем в строку символ ‘-‘, а затем инвертируем число и преобразуем как беззнаковое.

;Процедура преобразования слова в строку в десятичном виде (со знаком)
; AX - слово
; DI - буфер для строки (6 символов). Значение регистра не сохраняется.
word_to_sdec_str:
    push ax
    test ax,ax              ;Проверка знака AX
    jns wtsds_no_sign       ;Если >= 0, преобразуем как беззнаковое
    mov byte[di],'-'        ;Добавление знака в начало строки
    inc di                  ;Инкремент DI
    neg ax                  ;Изменение знака значения AX
wtsds_no_sign:
    call word_to_udec_str   ;Преобразование беззнакового значения
    pop ax
    ret

;Процедура преобразования слова в строку в десятичном виде (со знаком) ; AX — слово ; DI — буфер для строки (6 символов). Значение регистра не сохраняется. word_to_sdec_str: push ax test ax,ax ;Проверка знака AX jns wtsds_no_sign ;Если >= 0, преобразуем как беззнаковое mov byte[di],’-‘ ;Добавление знака в начало строки inc di ;Инкремент DI neg ax ;Изменение знака значения AX wtsds_no_sign: call word_to_udec_str ;Преобразование беззнакового значения pop ax ret

;Процедура преобразования байта в строку в десятичном виде (со знаком)
; AL - байт.
; DI - буфер для строки (4 символа). Значение регистра не сохраняется.
byte_to_sdec_str:
    push ax
    movsx ax,al             ;Преобразование байта в слово (со знаком)
    call word_to_sdec_str   ;Вызов процедуры для слова со знаком
    pop ax
    ret

;Процедура преобразования байта в строку в десятичном виде (со знаком) ; AL — байт. ; DI — буфер для строки (4 символа). Значение регистра не сохраняется. byte_to_sdec_str: push ax movsx ax,al ;Преобразование байта в слово (со знаком) call word_to_sdec_str ;Вызов процедуры для слова со знаком pop ax ret

Полный исходный код примера: printdec.asm. Результат работы программы выглядит вот так:

Как вывести на консоль в десятичном виде очень большое число (> 32 бит) читайте здесь.

Вывод чисел в восьмеричном виде

Выводить числа в восьмеричном виде приходится достаточно редко, поэтому подробно описывать не буду. Можно либо делить число последовательно на 8, либо преобразовывать в цифры группы по 3 бита. Я использовал второй вариант. Смотрите код примера: printoct.asm. Результат работы программы:

Вывод чисел в других системах счисления

Реализуется также, как вывод в десятичном виде – с помощью алгоритма последовательного деления на основание системы счисления. Например, если вам нужно вывести число в пятеричной системе счисления, делить надо на 5, а не на 10.

Упражнение

Напишите программу для вывода на консоль массива слов со знаком в десятичном виде (например, через запятую). Для вывода чисел можете воспользоваться моим примером или написать свою собственную процедуру. Результаты можете писать в комментариях.

Ещё раз ссылки на все примеры

  • printbin.asm – вывод чисел на консоль в двоичном виде
  • printoct.asm – вывод чисел на консоль в восьмеричном виде
  • printdec.asm – вывод чисел на консоль в десятичном виде (со знаком и без знака)
  • printhex.asm – вывод чисел на консоль в шестнадцатеричном виде

Следующая часть »

Ассемблер — SBP-Program

Что такое Ассемблер?

Процессорами управляют с помощью машинных инструкций.

Программисту сложно использовать машинные инструкции для написания программ.

Здесь на помощь приходят языки Ассемблеров.

Различным семействам процессоров соответствуют различные языки Ассемблеров.

Программа для процессора пишится на Ассемблере, далее она транслируется в машинные коды.

Ассемблеры относятся к языкам низкого уровня.

Итак, рассмотрим программирование на Ассемблере. Но прежде вспомним системы счисления.

Двоичное счисление

В компьютерах применяется двоичная система счисления. Почему так? Электронные элементы, из которых построен компьютер, могут воспринимать электрический сигнал. Их состояние меняется в зависимости от наличия или отсутствия сигнала. Итак, важно — есть сигнал или нет сигнала, да или нет. Двоичное счисление хорошо описывает эту картину, ведь в нём имеются только две цифры: 0 и 1. У двоичных цифр есть специальное название — бит. Если вы не знакомы с двоичным счислением, то сейчас самый момент познакомиться. Без понимания двоичной системы счисления невозможно освоить язык Ассемблера. Простую статью по двоичному счислению см. здесь.

Шестнадцатеричное счисление

Шестнадцатеричное счисление применяется для упрощения работы с двоичной системой счисления. 4-ре двоичные цифры заменяются одной шестнадцатиричной, что здорово упрошает запись. В компьютерной технике широко используется шестнадцатиричное счисление. Если вы не знакомы с шестнадцатиричным счислением, то можете прочесть статью «Шестнадцатиричная система счисления», которая поможет вам разобраться в этой теме. Без понимания шестнадцатиричной системы счисления невозможно освоить язык Ассемблера.

Что такое «бит»?

Бит — это наименьшая единица информации. Слово «бит», по-английски bit, происходит от «binary digit», что значит «двоичная цифра». Бит может быть единицей или нулём, ведь в двоичной системе счисления имеются только две цифры: 0 и 1.

Что такое «байт»?

Байт — это набор, состоящий из 8-ми битов. Байт, как и бит, — это единица информации. Пример байта:

0 0 0 0 0 0 0 1

Биты в байте нумеруются справа налево, от нуля до семи. В примере самый правый бит содержит единицу, его номер — ноль, второй справа бит имеет номер один и содержит ноль и т.д.

В нашем примере в байте хранится двоичное число один. А какое двоичное число хранится в байте:

1 0 1 0 1 0 1 0

В этом байте хранится двоичное число 10101010. Какое десятичное число соответствует данному двоичному? Для ответа на этот вопрос каждый бит умножим на двойку в степени, равной номеру бита в байте:

1 * 27 + 0 * 26 + 1 * 25 + 0 * 24 + 1 * 23 + 0 * 22 + 1 * 21 + 0 * 20 =
128 + 0 + 32 + 0 + 8 + 0 + 2 + 0 = 170

Бит S

Если целое число имеет знак, то крайний левый бит, т.е. старший бит, содержит указатель на знак числа. Если в старшем бите хранится число 0, то данное число является положительным, а если 1, то отрицательным. В этом случае старший бит называется бит S или знаковый бит.

Представление отрицательных чисел в компьютере

Чтобы записать отрицательное число нужно:
1. Инвертировать биты числа, т.е. нули заменить единицами, а единицы нулями;
2. К полученному числу прибавить единицу.

Пример. Дано двоичное число 01101010, его десятичное представление равно 106. Получим из него отрицательное число, для этого инвертируем исходное число:

01101010 — > 10010101

т.е. нули заменены единицами, а единицы нулями. Далее к полученному числу добавляем единицу:

10010101 + 00000001 = 10010110

Получили отрицательное представление исходного двоичного числа, обратите внимание, что сарший бит, крайний слева, 10010110, равен единице, а это говорит, что число отрицательное.

Для нахождения модуля полученного отрицательного числа также нужно инвертировать биты и добавить единицу. Инвертируем:

10010110 — > 01101001

добавляем единицу:

01101001 + 0000001 = 01101010

Получили модуль числа 10010110. Обратите внимание, что старший бит модуля 01101010 равен нулю, а это говорит, что число положительное.

Представление вещественных чисел в нормализованном виде

Число педставляют в виде:

pn * m

где p – основание системы счисления,
n – порядок, это показатель степени, представленный целым числом,
m — мантисса.

Такова форма представления чисел, её ещё называют представлением чисел с плавающей запятой. Таким образом вещественное число записывается в виде двух чисел: порядка и мантиссы.

Кроме того один бит нужен для указания знака числа.

Знак может иметь и порядок, чтоб учесть это к порядку добавляют смещение. Порядок плюс смещение называются характеристикой. Для одинарной точности (single precision) смещение равно 127, значит, если в характеристике хранится 127, то порядок равен нулю, т.к. 127 — 127 = 0. Если в характеристике хранится 135, то порядок равен 135 — 127 = 8. Если в характеристике хранится число 126, значит порядок равен 126 — 127 = -1. Так за счет смещения учитывается знак порядка, а значит нет необходимости в дополнительном знаковом бите для порядка.

Для двойной точности (double precision) смещение равно 1023.

Теперь что такое нормализованный вид числа. Для примера рассмотрим число десятичное 18,5. Представим его в нормализованном виде:

102 * 0,185

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

Другой пример представления числа в нормализованном виде. Дано число 0,0123, представить его в нормализованном виде. Делаем так:

10-1 * 0,123

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

Вот почему используется термин «числа с плавающей запятой», запятая перемещается для получения нормализованного вида числа.

А теперь рассмотрим представление двоичных чисел в нормализованном виде. Дано число 0,01b, представить его в нормализованном виде. Получаем:

2-2 * 1.0b

Нормализованное двоичное число должно начинаться с единицы. Основание двоичной системы равно двум, поэтому двойку возводим в степень. Остальное подобно примерам с десятичными числами.

Так как нормализованное двоичное число всегда должно начинаться с единицы, то её подразумевают, а фактически записывают только дробную часть двоичного числа. Это высвобождает один дополнительный бит для представления мантиссы.

Assembler: 45. Арифметические команды сопроцессора

Данная группа команд реализует четыре основные арифметические операции – сложение, вычитание, умножение и деление. С точки зрения типов операндов, арифметические команды можно разделить на работающие с целыми и вещественными операндами.

Арифметические команды имеют следующий формат Fppp (для вещественных операндов) или FIppp (для целочисленных операндов), где ррр может принимать значения:

  • ADD – сложение
  • SUB – вычитание
  • SUBR – обратное вычитание
  • MUL – умножение
  • DIV – деление
  • DIVR – обратное деление

Возможны следующие комбинации операндов:
Fppp (FIppp) — выполняет операцию над ST(0) — приемник и ST(1) — источник. Результат заносится в регистр стека сопроцессора ST(0).

Fppp (FIppp) — выполняет операцию над значением ST(0) и источником. Результат заносится в регистр стека сопроцессора ST(0).
Fppp (FIppp) , — выполняет операцию над значением в регистре стека сопроцессора ST(i) и значением в вершине стека ST(0). Результат заносится в регистр ST(i).

FpppP (FIpppР) , — операция выполняется аналогично предыдущей команде, только последним действием команды является выталкивание значения из вершины стека сопроцессора ST(0). Результат сложения остается в регистре ST(i-1).

В чем заключается «обратность» вычитания и деления?
Проанализируйте описание этих двух команд и Вам все станет понятно:
FSUB st(i), st — команда вычитает значение в вершине стека SТ(0) из значения в регистре стека сопроцессора ST(i). Результат вычитания запоминается в регистре стека сопроцессора ST(i).
FSUBR st(i),st — команда вычитает значение в вершине стека ST(0) из значения в регистре стека сопроцессора ST(i). Результат вычитания запоминается в вершине стека сопроцессора — регистре ST(0).

Пример: сложение трех чисел:
.data
Sarray dd 1.5, 3.4, 6.6  ;объявим массив вещественных чисел, котрые мы хотим сложить
Sum dd ?  ;зарезервируем место для результата
.code 
Finit  ;инициализируем сопроцессор
Fld Sarray   ;загрузим первый элемент Sarray
Fadd Sarray+4  ;прибавим к вершине второй элемнт массива
Fadd Sarray+8  ;и третий туда же
Fstp Sum  ;выгрузим значение из вершины стека сопроцессора в переменную Sum  

Дополнительные арифметические команды

  • FSQRT ; извлечение квадратного корня
  • FSCALE ; масштабирование ST(0) = ST(0)*2ST(1), ST(1) – целое число
  • FPREM ; вычисляет частичный остаток ST(0) = ST(0) — q*ST(1), где q – целая часть результата ST(0)/ST(1)
  • FPREM1 ; вычисляет частичный остаток ST(0) = ST(0) — q*ST(1), где q – ближайшее к ST(0)/ST(1) целое число
  • FPNDINT ; округление до целого
  • FXTRACT ; расцепляет число на — порядок, который заменяет число в ST(1), мантиссу, которая помещается в ST(0)
  • FABS ; получение модуля числа
  • FCHS ; изменение знака числа

Глава 3. Модульное программирование (ассемблер)


Вы можете изучить и скачать доклад-презентацию на тему Глава 3. Модульное программирование (ассемблер). Презентация на заданную тему содержит 82 слайдов. Для просмотра воспользуйтесь проигрывателем, если материал оказался полезным для Вас — поделитесь им с друзьями с помощью социальных кнопок и добавьте наш сайт презентаций в закладки!

Слайды и текст этой презентации

Слайд 1
Описание слайда:

Глава 3 Модульное программирование МГТУ им. Н.Э. Баумана Факультет Информатика и системы управления Кафедра Компьютерные системы и сети Лектор: д.т.н., проф. Иванова Галина Сергеевна


Слайд 2
Описание слайда:

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



Слайд 3
Описание слайда:

Команды вызова процедуры и возврата управления 1. Команда вызова процедуры: CALL rel32/r32/m32 ; вызов внутрисегментной ; процедуры (near — ближний ) CALL sreg:r32/m48 ; вызов межсегментной процедуры ; (far — дальний ) 2. Команда возврата управления: RET [<Целое>] где <Целое> – количество байт, извлекаемых из стека при возврате управления – используется для удаления из стека параметров процедуры (см. далее). При выполнении команды вызова процедуры автоматически в стек заносится адрес команды, следующей за командой вызова процедуры, – адрес возврата. Команда возврата управления выбирает этот адрес из стека и осуществляет переход по нему.


Слайд 4
Описание слайда:

Организация передачи управления в процедуру


Слайд 5
Описание слайда:

Описание процедуры В отличие от языков высокого уровня, ассемблер не требует специального оформления процедур. На любой адрес программы можно передать управление командой вызова процедуры, и оно вернется к вызвавшей процедуре, как только встретится команда возврата управления. Такая организация может привести к трудночитаемым программам, поэтому в язык Ассемблера включены директивы логического оформления процедур. Для описания процедуры используются специальные директивы начала и завершения. В минимальной форме (при опущенных операндах) они выглядят так: <Имя процедуры> PROC <Тело процедуры> <Имя процедуры> ENDP


Слайд 6
Описание слайда:

Пример 3. 1 Процедура MaxDword () .CONST MsgExit DB «Press Enter to Exit»,0AH,0DH,0 .DATA A DWORD 56 B DWORD 34 .DATA? D DWORD ? inbuf DB 100 DUP (?) .CODE Start: call MaxDword ; вызов процедуры XOR EAX,EAX Invoke StdOut,ADDR MsgExit Invoke StdIn,ADDR inbuf,LengthOf inbuf Invoke ExitProcess,0 END Start


Слайд 7
Описание слайда:

Текст процедуры MaxDword PROC push EAX ; сохранить регистр push EBX ; сохранить регистр lea EBX,D; загрузить адрес результата mov EAX,A; загрузить первое число в регистр cmp EAX,B ; сравнить числа jg con ; если первое больше, то на запись mov EAX,B; загрузить второе число в регистр con: mov [EBX],EAX ; записать результат pop EBX ; восстановить регистр pop EAX ; восстановить регистр ret ; вернуть управление MaxDword ENDP


Слайд 8
Описание слайда:

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


Слайд 9
Описание слайда:

3.2.1 Передача параметров в регистрах Пример 3.2 a. Определение суммы двух целых чисел .DATA A DWORD 56 B DWORD 34 .DATA? D DWORD ? inbuf DB 100 DUP (?) .CODE Start: ; Занесение параметров в регистры lea EDX,D ; адрес результата mov EAX,A ; первое число mov EBX,B ; второе число call SumDword ; вызов процедуры Invoke StdOut,ADDR MsgExit Invoke StdIn,ADDR inbuf,LengthOf inbuf Invoke ExitProcess,0


Слайд 10
Описание слайда:

Процедура, получающая параметры в регистрах SumDword PROC add EAX,EBX mov [EDX],EAX ret SumDword ENDP ; завершение модуля End Start Процедуры, получающие параметры в регистрах, используется, если количество параметров невелико, и в программе на ассемблере можно найти соответствующее количество незанятых регистров.


Слайд 11
Описание слайда:

3.2.2 Процедуры с глобальными переменными (совместная трансляция) При совместной трансляции, когда основная программа и процедура объединены в один исходный модуль, ассемблер строит общую таблицу символических имен. Следовательно, и основная программа и процедура могут обращаться к символическим именам, объявленным в том же модуле. Способ не технологичен: процедуры не универсальны; большое количество ошибок.


Слайд 12
Описание слайда:

Процедура, работающая с глобальными переменными при совместной трансляции Пример 3.2 b. Определение суммы двух чисел. .DATA A DWORD 56 ; первое число B DWORD 34 ; второе число .DATA? D DWORD ? ; место для результата .CODE Start: call SumDword . . . SumDword PROC

Ассемблер — Википедия. Что такое Ассемблер

Эта статья — о компьютерных программах. О языке программирования см. Язык ассемблера.

Ассе́мблер (от англ. assembler — сборщик) — транслятор исходного текста программы, написанной на языке ассемблера, в программу на машинном языке.

Как и сам язык, ассемблеры, как правило, специфичны для конкретной архитектуры, операционной системы и варианта синтаксиса языка. Вместе с тем существуют мультиплатформенные или вовсе универсальные (точнее, ограниченно-универсальные, потому что на языке низкого уровня нельзя написать аппаратно-независимые программы) ассемблеры, которые могут работать на разных платформах и операционных системах. Среди последних можно также выделить группу кросс-ассемблеров, способных собирать машинный код и исполняемые модули (файлы) для других архитектур и операционных систем.

Ассемблирование может быть не первым и не последним этапом на пути получения исполнимого модуля программы. Так, многие компиляторы с языков программирования высокого уровня выдают результат в виде программы на языке ассемблера, которую в дальнейшем обрабатывает ассемблер. Также результатом ассемблирования может быть не исполняемый, а объектный модуль, содержащий разрозненные блоки машинного кода и данных программы, из которого (или из нескольких объектных модулей) в дальнейшем с помощью редактора связей может быть получен исполнимый файл.

Архитектура x86

Ассемблеры для DOS

Наиболее известными ассемблерами для операционной системы DOS являлись Borland Turbo Assembler (TASM), Microsoft Macro Assembler (MASM) и Watcom Assembler (WASM). Также в своё время был популярен простой ассемблер A86.

Windows

При появлении операционной системы Windows появилось расширение TASM, именуемое TASM 5+ (неофициальный пакет, созданный человеком с ником !tE’), позволившее создавать программы для выполнения в среде Windows. Последняя известная версия TASM — 5.3, поддерживающая инструкции MMX, на данный момент включена в Turbo C++ Explorer. Но официально развитие программы полностью остановлено. Последнее развитие компилятор получил благодаря современной среде разработки TASM Visual. Среда неофициальная, но с её помощью работа с компилятором многократно упрощается.

Microsoft поддерживает свой продукт под названием Microsoft Macro Assembler. Она продолжает развиваться и по сей день, последние версии включены в наборы DDK. Но версия программы, направленная на создание программ для DOS, не развивается. Кроме того, Стивен Хатчессон создал пакет для программирования на MASM под названием «MASM32».

GNU и Linux

В состав операционной системы GNU входит пакет binutils, включающий в себя ассемблер gas (GNU Assembler), использующий AT&T-синтаксис, в отличие от большинства других популярных ассемблеров, которые используют Intel-синтаксис (поддерживается с версии 2.10).

Переносимые ассемблеры

Также существует открытый проект ассемблера, версии которого доступны под различные операционные системы, и который позволяет получать объектные файлы для этих систем. Называется этот ассемблер NASM (Netwide Assembler).

Yasm — это переписанная с нуля версия NASM под лицензией BSD (с некоторыми исключениями).

flat assembler (fasm) — молодой ассемблер под модифицированной для запрета перелицензирования (в том числе под GNU GPL) BSD-лицензией. Есть версии для KolibriOS, Linux, DOS и Windows; использует Intel-синтаксис и поддерживает инструкции x86-64.

Архитектуры RISC

MCS-51

MCS-51 (Intel 8051) — классическая архитектура микроконтроллера. Для неё существует кросс-ассемблер ASM51, выпущенный корпорацией MetaLink.

Кроме того, многие фирмы-разработчики программного обеспечения, такие, как IAR или Keil, представили свои варианты ассемблеров. В ряде случаев применение этих ассемблеров оказывается более эффективным благодаря удобному набору директив и наличию среды программирования, объединяющей в себе профессиональный ассемблер и язык программирования Си, отладчик и менеджер программных проектов.

Пример программы на языке ASM-51 для микроконтроллера AT89S52:

 
mov SCON, #50h
mov Th2, #0FDh
orl TMOD, #20h
setb TR1
again:
  clr RI
  jnb RI, $
  mov A, SBUF
  jnb RI, $
  clr TI
  mov SBUF, A
  jnb TI, $
sjmp again

Данная программа отправляет обратно полученный символ, через последовательный порт UART.

AVR

На данный момент для AVR существуют 4 компилятора производства Atmel (AVRStudio 3, AVRStudio 4, AVRStudio 5 и AVRStudio 6).

В рамках проекта AVR-GCC (он же WinAVR) существует компилятор avr-as (это портированный под AVR ассемблер GNU as из GCC).

Также существует свободный минималистический компилятор avra[1].

Платные компиляторы: IAR (EWAVR), CodeVisionAVR, Imagecraft. Данные компиляторы поддерживают языки Assembler и C, а IAR ещё и C++.

Существует компилятор с языка BASIC — BASCOM, также платный.

ARM

Для процессоров ARM существует достаточно широкий выбор компиляторов, внутренняя реализация которых зависит от непосредственно производителя данного ARM-процессора либо разработчика IDE для работы с ARM-процессорами. Официальным компилятором ARM, непосредственно от компании ARM, является ARM Compiler 6, который входит в IDE DS-5 Development Studio и поддерживает компиляцию программ на языках Си и С++.
Компиляторы от поставщиков ARM процессоров и разработчиков ARM toolchain:


Примеры компиляции С в ARM Assembler
Битовые операции

Си:

ASM:

ADR r4,a ; get address for a
LDR r0,[r4] ; get value of a
MOV r0,r0,LSL#2 ; perform shift
ADR r4,b ; get address for b
LDR r1,[r4] ; get value of b
AND r1,r1,#15 ; perform AND
ORR r1,r0,r1 ; perform OR
ADR r4,z ; get address for z
STR r1,[r4] ; store value for z
Ветвления

Си:

if (i == 0)
{
    i = i + 10;
}

ASM:

@(переменная i находится в регистре R1)
SUBS R1, R1, #0
ADDEQ R1, R1, #10
Циклы

Си:

for ( i = 0 ; i < 15 ; i++)
{
    j = j + j;
}

ASM:

      SUB R0, R0, R0 ; i -> R0 and i = 0
start CMP R0, #15 ; is i < 15?
      ADDLT R1, R1, R1 ; j = j + j
      ADDLT R0, R0, #1 ; i++
      BLT start

PIC

Пример программы на языке ассемблера для микроконтроллера PIC16F628A (архитектура PIC):

 
        LIST    p=16F628A
         __CONFIG 0309H 
 
STATUS  equ     0x003
TRISB   equ     0x086
PORTB   equ     0x006
RP0     equ     5
        org  0
        goto start
start:
        bsf     STATUS,RP0             
        movlw   . 00      
        movwf   TRISB                    
        bcf     STATUS,RP0        
led:
        movlw   .170   
        movwf   PORTB
        goto    led
end

AVR32

MSP430

Пример программы на языке Assembler для микроконтроллера MSP430G2231 (архитектура MSP, в среде Code Composer Studio):

 
 .cdecls C,LIST,  "msp430g2231.h"
;------------------------------------------------------------------------------
            .text                           ; Program Start
;------------------------------------------------------------------------------
RESET       mov.w   #0280h,SP               ; Initialize stackpointer
StopWDT     mov.w   #WDTPW+WDTHOLD,&WDTCTL  ; Stop WDT
SetupP1     bis.b   #001h,&P1DIR            ; P1.0 output
                                            ;				          			
Mainloop    bit.b   #010h,&P1IN             ; P1.4 hi/low?
            jc      ON                      ; jmp--> P1.4 is set
                                            ;
OFF         bic. b   #001h,&P1OUT            ; P1.0 = 0 / LED OFF
            jmp     Mainloop                ;
ON          bis.b   #001h,&P1OUT            ; P1.0 = 1 / LED ON
            jmp     Mainloop                ;
                                            ;
;------------------------------------------------------------------------------
;           Interrupt Vectors
;------------------------------------------------------------------------------
            .sect   ".reset"                ; MSP430 RESET Vector
            .short  RESET                   ;
            .end

PowerPC

Программный пакет The PowerPC Software Development Toolset от IBM включает в себя ассемблер для PowerPC.

MIPS

Макроассемблер

Макроассемблер (от греч. μάκρος — большой, обширный) — макропроцессор, базовым языком которого является язык ассемблера[2].

Ассемблирование и компилирование

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

См. также

Примечания

Литература

  • Вострикова З. П. Программирование на языке ассемблера ЕС ЭВМ. М.: Наука, 1985.
  • Галисеев Г. В. Ассемблер для Win 32. Самоучитель. — М.: Диалектика, 2007. — С. 368. — ISBN 978-5-8459-1197-1.
  • Зубков С. В. Ассемблер для DOS, Windows и UNIX. — М.: ДМК Пресс, 2006. — С. 608. — ISBN 5-94074-259-9.
  • Ирвин Кип. Язык ассемблера для процессоров Intel = Assembly Language for Intel-Based Computers. — М. : Вильямс, 2005. — С. 912. — ISBN 0-13-091013-9.
  • Калашников О. А. Ассемблер? Это просто! Учимся программировать. — БХВ-Петербург, 2011. — С. 336. — ISBN 978-5-9775-0591-8.
  • Магда Ю. С. Ассемблер. Разработка и оптимизация Windows-приложений. СПб.: БХВ-Петербург, 2003.
  • Нортон П., Соухэ Д. Язык ассемблера для IBM PC. М.: Компьютер, 1992.
  • Владислав Пирогов. Ассемблер для Windows. — СПб.: БХВ-Петербург, 2002. — 896 с. — ISBN 978-5-9775-0084-5.
  • Владислав Пирогов. Ассемблер и дизассемблирование. — СПб.: БХВ-Петербург, 2006. — 464 с. — ISBN 5-94157-677-3.
  • Сингер М. Мини-ЭВМ PDP-11: Программирование на языке ассемблера и организация машины. М.: Мир, 1984.
  • Скэнлон Л. Персональные ЭВМ IBM PC и XT. Программирование на языке ассемблера. М.: Радио и связь, 1989.
  • Юров В., Хорошенко С. Assembler: учебный курс.  — СПб.: Питер, 2000. — С. 672. — ISBN 5-314-00047-4.

Версия сборки | Документы Microsoft

  • 3 минуты на чтение

В этой статье

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

Примечание

Управление версиями выполняется только для сборок со строгими именами.

Среда выполнения выполняет несколько шагов для разрешения запроса привязки сборки:

  1. Проверяет исходную ссылку на сборку, чтобы определить версию сборки, которую нужно связать.

  2. Проверяет наличие всех применимых файлов конфигурации для применения политики версий.

  3. Определяет правильную сборку из ссылки на исходную сборку и любого перенаправления, указанного в файлах конфигурации, а также определяет версию, которая должна быть привязана к вызывающей сборке.

  4. Проверяет глобальный кеш сборок, кодовые базы, указанные в файлах конфигурации, а затем проверяет каталог и подкаталоги приложения, используя правила проверки, описанные в разделе Как среда выполнения обнаруживает сборки.

На следующем рисунке показаны эти шаги:

Дополнительные сведения о настройке приложений см. В разделе Настройка приложений. Дополнительные сведения о политике привязки см. В разделе Как среда выполнения обнаруживает сборки.

Информация о версии

Каждая сборка имеет два разных способа представления информации о версии:

  • Номер версии сборки, который вместе с именем сборки и информацией о культуре является частью удостоверения сборки. Это число используется средой выполнения для обеспечения соблюдения политики версий и играет ключевую роль в процессе разрешения типов во время выполнения.

  • Информационная версия, которая представляет собой строку, представляющую дополнительную информацию о версии, включенную только в информационных целях.

Номер версии сборки

Каждая сборка имеет номер версии как часть идентификатора. Таким образом, две сборки, которые различаются по номеру версии, рассматриваются средой выполнения как совершенно разные сборки. Этот номер версии физически представлен в виде строки из четырех частей в следующем формате:

< основная версия >. < дополнительная версия >. <Номер сборки >. < ревизия >

Например, версия 1.5.1254.0 указывает 1 как основную версию, 5 как вспомогательную версию, 1254 как номер сборки и 0 как номер редакции.

Номер версии хранится в манифесте сборки вместе с другой идентификационной информацией, включая имя сборки и открытый ключ, а также информацию о взаимосвязях и идентификаторах других сборок, связанных с приложением.

Когда сборка построена, средство разработки записывает информацию о зависимостях для каждой сборки, на которую имеется ссылка в манифесте сборки.Среда выполнения использует эти номера версий вместе с информацией о конфигурации, установленной администратором, приложением или издателем, для загрузки правильной версии сборки, на которую имеется ссылка.

Среда выполнения различает сборки с обычными и строгими именами для целей управления версиями. Проверка версий происходит только со сборками со строгими именами.

Дополнительные сведения об указании политик привязки версий см. В разделе Настройка приложений. Дополнительные сведения о том, как среда выполнения использует информацию о версии для поиска конкретной сборки, см. В разделе Как среда выполнения обнаруживает сборки.

Сборочная информационная версия

Информационная версия — это строка, которая присоединяет дополнительную информацию о версии к сборке только в информационных целях; эта информация не используется во время выполнения. Текстовая информационная версия соответствует маркетинговой литературе продукта, упаковке или названию продукта и не используется средой выполнения. Например, информационной версией может быть «Common Language Runtime версии 1.0» или «NET Control SP 2». На вкладке «Версия» диалогового окна свойств файла в Microsoft Windows эта информация отображается в элементе «Версия продукта».

Примечание

Хотя вы можете указать любой текст, при компиляции появится предупреждающее сообщение, если строка не соответствует формату, используемому в номере версии сборки, или если она имеет этот формат, но содержит подстановочные знаки. Это предупреждение безвредно.

Информационная версия представлена ​​с помощью настраиваемого атрибута System.Reflection.AssemblyInformationalVersionAttribute. Дополнительные сведения об атрибуте информационной версии см. В разделе Установка атрибутов сборки.

См. Также

Программа на языке ассемблера для поиска наибольшего числа в массиве

Программа на языке ассемблера для поиска наибольшего числа в массиве

Задача — Определить наибольшее число в массиве из n элементов.Значение n хранится по адресу 2050, а массив начинается с адреса 2051. Результат сохраняется по адресу 3050. Начальный адрес программы принимается равным 2000.

Пример —

Алгоритм —

  1. Мы берем первый элемент массива в A
  2. Сравнение A с другими элементами массива, если A меньше, то сохранить этот элемент в A, в противном случае сравнить со следующим элементом
  3. Значение A — это ответ

Программа —



Адрес памяти Мнемоника Комментарий
2000 LXI H 2050 H ← 20, L ← 50
2003 MOV C, M С ← M
2004 DCR С С ← С-01
2005 INX H HL ← HL + 0001
2006 MOV A, M A ← M
2007 INX H HL ← HL + 0001
2008 CMP M А-М
2009 JNC 200D Если флаг переноса = 0, перейти к 200D
200C MOV A, M A ← M
200D DCR С С ← С-1
200E JNZ 2007 Если нулевой флаг = 0, перейти к 2007
2011 STA 3050 А → 3050
2014 HLT

Пояснение — Используемые регистры: A, H, L, C

  1. LXI 2050 назначает 20 H и 50 L
  2. MOV C, M копирует содержимое памяти (указанное парой регистров HL) в C (используется как счетчик)
  3. DCR C уменьшает значение C на 1
  4. INX H увеличивает значение HL на 1. Это делается для посещения следующей ячейки памяти
  5. MOV A, M копирует содержимое памяти (заданное парой регистров HL) в A
  6. INX H увеличивает значение HL на 1. Это делается для посещения следующей ячейки памяти
  7. CMP M сравнивает A и M, вычитая M из A. Флаг переноса и знак знака устанавливается, если A-M отрицательное
  8. JNC 200D переводит программный счетчик на 200D, если флаг переноса = 0
  9. MOV A, M копирует содержимое памяти (заданное парой регистров HL) в A
  10. DCR C уменьшает значение C на 1
  11. JNZ 2007 переводит программный счетчик на 2007, если нулевой флаг = 0
  12. STA 3050 сохраняет значение A в ячейке памяти 3050
  13. HLT останавливает выполнение программы и останавливает любое дальнейшее выполнение

Вниманию читателя! Не прекращайте учиться сейчас.Освойте все важные концепции DSA с помощью курса DSA Self Paced Course по доступной для студентов цене и будьте готовы к работе в отрасли.

Руководство пользователя ассемблера

: LDR (немедленное смещение)

Загрузить с немедленным смещением, немедленным смещением с предварительной индексацией или немедленным смещением после индексации.

Синтаксис

LDR { тип } { конд } Rt , [ Rn {, # смещение }]; немедленный смещение

LDR { тип } { конд } Rt , [ Rn , # смещение ]! ; предварительно индексированные

LDR { тип } { конд } Rt , [ Rn ], # смещение ; после индексации

LDRD { конд } Rt , Rt2 , [ Rn {, # смещение }]; немедленный смещение, двойное слово

LDRD { конд } Rt , Rt2 , [ Rn , # смещение ]! ; предварительно индексированные, двойное слово

LDRD { конд } Rt , Rt2 , [ Rn ], # смещение ; постиндексированный, двойное слово

где:

тип

может быть любым из:

B

байт без знака (ноль расширяется до 32 бит при загрузке. )

SB

байт со знаком (только LDR . Знак расширяется до 32 бит.)

H

Полуслово без знака (Ноль расширяется до 32 бит при загрузке.)

SH

подпись Halfword (только LDR . Знак расширяется до 32 бит.)

опущено для Word.

конд

— необязательный код условия.

Rt

— это регистр для загрузки.

Rn

— это регистр, на котором основан адрес памяти.

смещение

— это смещение. Если смещение равно опущен, адрес является содержимым Rn .

RT2

— дополнительный регистр для загрузки двойного слова операции.

Не все опции доступны в каждом наборе команд и архитектура.

Диапазоны смещения и архитектуры

В следующей таблице показаны диапазоны смещений и доступность этих инструкций:

Таблица 10-10 Смещения и архитектуры, LDR, слово, полуслова и байт

Инструкция Немедленное смещение Предварительно проиндексировано Пост-индексирование Arch.
ARM, слово или байт a –4095 до 4095 –4095 до 4095 –4095 до 4095 Все
ARM, байт со знаком, полуслово или полуслово со знаком –255 до 255 –255 до 255 –255 до 255 Все
РУКА, двойное слово –255 до 255 –255 до 255 –255 до 255 5E
32-битное кодирование большого пальца, слово, полуслово, полуслово со знаком, байт или байт со знаком а –255 до 4095 –255 до 255 –255 до 255 Т2
32-битное кодирование большого пальца, двойное слово –1020 до 1020 b –1020 до 1020 b –1020 до 1020 b Т2
16-битное кодирование большого пальца, слово c 0 до 124 b Не доступен Не доступен Т
16-битное кодирование большого пальца, полуслово без знака c 0 до 62 d Не доступен Не доступен Т
16-битное кодирование большого пальца, беззнаковый байт c 0 до 31 Не доступен Не доступен Т
16-битное кодирование большого пальца, слово, Rn is SP e 0 до 1020 b Не доступен Не доступен Т

Заметки о колонке «Архитектура»

Записи в столбце «Архитектура» указывают на то, что инструкции в наличии:

Все

Все версии архитектуры ARM.

5E

Архитектуры ARMv5TE, ARMv6 * и ARMv7.

Т2

Архитектуры ARMv6T2 и выше.

Т

Архитектуры ARMv4T, ARMv5T *, ARMv6 * и ARMv7.

Регистр ограничений

R n должен отличаться от R t дюйм формы до и после индексации.

Ограничения регистра двойного слова

R n должен отличаться от R t2 дюйм формы до и после индексации.

Для инструкций Thumb не следует указывать SP или ПК для либо Rt , либо Rt2 .

Для инструкций ARM:

Использование ПК

В коде ARM вы можете использовать ПК для R t в LDR Word инструкции и ПК для R n in LDR инструкции.

Настоящие инструкции ARM не позволяют использовать ПК в других целях.

В коде большого пальца вы можете использовать ПК для R t в LDR Word инструкции и ПК для R n in LDR инструкции. Другое использование ПК в этих инструкциях Thumb не разрешено.

Использование SP

Вы можете использовать SP для R n .

В коде ARM вы можете использовать SP для R t в текстовых инструкциях.Вы можно использовать SP для R t в несловных инструкциях в коде ARM, но это устарела в ARMv6T2 и более поздних версиях.

В коде большого пальца вы можете использовать SP для R t в текстовых инструкциях только. Любое другое использование SP для R t в этой инструкции не разрешено в коде Thumb.

Примеры

    LDR r8, [r10]; загружает R8 с адреса в R10. 
    LDRNE r2, [r5, # 960]! ; (условно) загружает R2 из слова
                            ; 960 байт выше адреса в R5, и
                            ; увеличивает R5 на 960.

Лучший номер сборки — отличные предложения по номеру сборки от глобальных продавцов номеров сборки

Отличная новость !!! Номер сборки вы попали в нужное место. К настоящему времени вы уже знаете, что что бы вы ни искали, вы обязательно найдете это на AliExpress. У нас буквально тысячи отличных продуктов во всех товарных категориях. Ищете ли вы товары высокого класса или дешевые и недорогие оптовые закупки, мы гарантируем, что он есть на AliExpress.

Вы найдете официальные магазины торговых марок и небольших независимых продавцов со скидками, которые предлагают быструю доставку, надежные, а также удобные и безопасные способы оплаты, независимо от того, сколько вы решите потратить.

AliExpress никогда не уступит по выбору, качеству и цене.Каждый день вы будете находить новые онлайн-предложения, скидки в магазинах и возможность сэкономить еще больше, собирая купоны. Но вам, возможно, придется действовать быстро, поскольку этот лучший номер сборки в кратчайшие сроки станет одним из самых востребованных бестселлеров. Подумайте, как вам будут завидовать друзья, когда вы скажете им, что получили номер сборки на AliExpress. Благодаря самым низким ценам в Интернете, дешевым тарифам на доставку и возможности получения на месте вы можете еще больше сэкономить.

Если вы все еще не уверены в номере сборки и думаете о выборе аналогичного товара, AliExpress — отличное место для сравнения цен и продавцов. Мы поможем вам разобраться, стоит ли доплачивать за высококачественную версию или вы получаете столь же выгодную сделку, приобретая более дешевую вещь. А если вы просто хотите побаловать себя и потратиться на самую дорогую версию, AliExpress всегда позаботится о том, чтобы вы могли получить лучшую цену за свои деньги, даже сообщая вам, когда вам будет лучше дождаться начала рекламной акции. и ожидаемая экономия.AliExpress гордится тем, что у вас всегда есть осознанный выбор при покупке в одном из сотен магазинов и продавцов на нашей платформе.Реальные покупатели оценивают качество обслуживания, цену и качество каждого магазина и продавца. Кроме того, вы можете узнать рейтинги магазина или отдельных продавцов, а также сравнить цены, доставку и скидки на один и тот же продукт, прочитав комментарии и отзывы, оставленные пользователями. Каждая покупка имеет звездный рейтинг и часто имеет комментарии, оставленные предыдущими клиентами, описывающими их опыт транзакций, поэтому вы можете покупать с уверенностью каждый раз. Короче говоря, вам не нужно верить нам на слово — просто слушайте миллионы наших довольных клиентов.

И, если вы новичок на AliExpress, мы откроем вам секрет. Непосредственно перед тем, как вы нажмете «купить сейчас» в процессе транзакции, найдите время, чтобы проверить купоны — и вы сэкономите еще больше. Вы можете найти купоны магазина, купоны AliExpress или собирать купоны каждый день, играя в игры в приложении AliExpress. Вместе с бесплатной доставкой, которую предлагают большинство продавцов на нашем сайте, мы думаем, вы согласитесь, что вы получите этот номер сборки по самой выгодной цене в Интернете.

У нас всегда есть новейшие технологии, новейшие тенденции и самые обсуждаемые лейблы. На AliExpress отличное качество, цена и сервис всегда в стандартной комплектации. Начните самый лучший шоппинг прямо здесь.

пользователей | Сборка Интернет

Агиар-Карри, Сесилия М.[править]

04 Демократ Связаться с членом Ассамблеи Сесилией М. Агияр-Карри

Офис Капитолия, комната 5144

P.O. Box 942849, Sacramento, CA 94249-0004; (916) 319-2004 edit

District Office

600 A Street, Suite D, Davis, CA 95616; (530) 757-1034 edit
2721 Napa Valley Corporate Drive, Napa, CA 94558; (707) 224-0440 edit
50 D Street, Suite 305, Santa Rosa, CA 95404; (707) 576-0400 редактировать
885 Lakeport Boulevard, Lakeport, CA 95453; редактировать

Добавить офис

Арамбула, д-р.Хоакин [править]

31 Демократ Связаться с членом Ассамблеи доктором Хоакином Арамбула

Офис Капитолия, комната 5155

P. O. Box 942849, Sacramento, CA 94249-0031; (916) 319-2031 edit

District Office

2550 Mariposa Mall, Room 5031, Fresno, CA 93721; (559) 445-5532 редактировать

Добавить офис

Бауэр-Кахан, Ребекка [править]

16 Демократ Связаться с членом Ассамблеи Ребеккой Бауэр-Кахан

Capitol Office, Room 2130

P.О. Box 942849, Сакраменто, Калифорния 94249-0016; (916) 319-2016 edit

District Office

2440 Camino Ramon, Suite 345, San Ramon, CA 94583; (925) 328-1515 редактировать

Добавить офис

Беннет, Стив [править]

37 Демократ Свяжитесь с членом Ассамблеи Стивом Беннеттом,

, Офис Капитолия, комната 6031

P. О. Box 942849, Сакраменто, Калифорния 94249-0037; (916) 319-2037 edit

District Office

101 West Anapamu Street, Suite A, Santa Barbara, CA 93101; (805) 564-1649 edit
89 South California Street, Suite F, Ventura, CA 93001; (805) 641-3700 редактировать

Добавить офис

Берман, Марк [править]

24 Демократ Связаться с членом Ассамблеи Марком Берманом

Capitol Office, Room 6011

P.О. Box 942849, Сакраменто, Калифорния 94249-0024; (916) 319-2024 edit

District Office

721 Colorado Ave, Suite 101, Los Altos, CA 94303; (650) 324-0224 редактировать

Добавить офис

Бигелоу, Фрэнк [править]

05 Республиканский Свяжитесь с членом Ассамблеи Фрэнком Бигелоу, офис Капитолия,

, комната 4158,

P. O. Box 942849, Сакраменто, CA 94249-0005; (916) 319-2005 edit

District Office

730 North I Street, Suite 102, Madera, CA 93637; (559) 673-0501 edit
2441 Headington Road, Placerville, CA 95667; (530) 295-5505 edit
460 Sutter Hill Road, Suite C, Sutter Creek, CA 95685; (209) 267-0500 редактировать

Добавить офис

Блум, Ричард [править]

50 Демократ Связаться с членом Ассамблеи Ричардом Блумом

Офис Капитолия, комната 2003

P.О. Box 942849, Сакраменто, Калифорния 94249-0050; (916) 319-2050 edit

District Office

2800 28th Street, Suite 105, Santa Monica, CA ; (310) 450-0041 редактировать

Добавить офис

Бурнер Хорват, Таша [править]

76 Демократ Связаться с членом Ассамблеи Ташей Боернер Хорват

Капитолий Офис, комната 4130

P. О. Box 942849, Сакраменто, Калифорния 94249-0076; (916) 319-2076 редактировать

Районный офис

325 Carlsbad Village Drive, Suite A-2, Carlsbad, CA 92008; (760) 434-7605 редактировать

Добавить офис

Бонта, Роб [править]

18 Демократ Связаться с членом Ассамблеи Роба Бонта

Capitol Office, комната 2148

P.О. Box 942849, Сакраменто, Калифорния 94249-0018; (916) 319-2018 edit

District Office

1515 Clay Street, Suite 2204, Oakland, CA 94612; (510) 286-1670 редактировать

Добавить офис

Берк, Отэм Р. [править]

62 Демократ Связаться с членом Ассамблеи Отем Р. Burke

Capitol Office, комната 5150

P.O. Box 942849, Sacramento, CA 94249-0062; (916) 319-2062 редактировать

Окружной офис

One Manchester Boulevard, Suite 601, Inglewood, CA ; (310) 412-6400 редактировать

Добавить офис

Кальдерон, Лиза [править]

57 Демократ Связаться с членом Ассамблеи Лизой Кальдерон

Capitol Office, Room 2175

P.О. Box 942849, Сакраменто, Калифорния 94249-0057; (916) 319-2057 редактировать

Районный офис

13181 Crossroads Parkway North, Suite 160, City of Industry, CA 91746-3497; (562) 692-5858 редактировать

Добавить офис

Каррильо, Венди [править]

51 Демократ Свяжитесь с членом Ассамблеи Венди Каррильо,

, Офис Капитолия, комната 4167

P.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *