Как
создать перемещаемый код — исследуем вопрос ……….Содержание: ……….Введение ……….Создание перемещаемого модуля ……….Подключение перемещаемого ассемблерного
модуля к проекту Введение……….Прежде всего, звучит вопрос: «Зачем всё это нужно?» ……….Отвечу на него в меру своего понимания. Когда вы только начинаете осваивать программирование на ассемблере для PIC микроконтроллеров и делаете свои первые проекты, модули вовсе не нужны, и вполне можно обходиться без них. ……….Если продолжаете программировать, и счёт вашим проектам идёт уже на десятки, то, возможно, вы начнёте замечать, что часто повторяете одни и те же действия со своим собственным кодом. То есть создаёте новый проект в MpLab, копируете в него пустой шаблон-заготовку для будущей программы, копируете в текст свои готовые программы и подпрограммы, а потом часть программы доделываете уже под конкретные задачи конкретного устройства. Чтобы избежать рутинных операций с копированием готового ассемблерного кода в новый проект, разработано несколько инструментов. ……….- Макроопределения (макросы) Модули применяются для
облегчения ……….Разработчики MpLab, в частности — ассемблера Mpasm, позаботились о том, чтобы облегчить программистам труд и создали систему, пользуясь которой, возможно создавать библиотеки своих собственных программ и легко подключать их к новым проектам. ……….В этой статье будет рассмотрен способ оформления и использования модулей ассемблерного кода для микроконтроллеров Microchip среднего семейства. Создание перемещаемого модуля……….При создании единичного проекта переменные задаются в фиксированных регистрах при помощи директив equ и cblock, а программа и подпрограммы сразу же размещаются в фиксированных адресах при помощи директивы org.……….При создании перемещаемого кода ситуация другая. Адреса для переменных и адреса размещения модулей кода назначаются автоматически в процессе компиляции проекта. ……….Это основное преимущество перемещаемого кода – он может располагаться в любых адресах и работать с регистрами в любых банках микроконтроллера (речь идёт о средней серии PIC16Fxxx, в которой присутствует страничная адресация ОЗУ). ……….Основное преимущество оборачивается и некоторой избыточностью. В перемещаемом коде нужно обеспечивать выбор нужного банка используемых регистров и учесть, что код может оказаться в любых страницах памяти программ. То есть нужно предустанавливать биты PR0, PR1, IRP регистра STATUS при работе с переменными и регистр PCLATH при вызове подпрограмм. ……….К
примеру, имеется две готовых подпрограммы, осуществляющих
математические операции, и мы задаёмся целью разместить их в отдельном
модуле, чтобы впоследствии его можно было включить в любой проект. Исходные подпрограммы……….Первая подпрограмма преобразует число в диапазоне 0…99 из двоичного кода в десятичный. Вторая делает обратное преобразование и из десятичного вида переводит число в двоичный код. ……….Подпрограммы сделаны для устройства с двухзначной динамической индикацией для ввода с клавиатуры и вывода на дисплей числа в диапазоне 0…99. Рассчитаны они на работу с нулевым банком регистров и в нулевой странице памяти программ. ……….Вот эти подпрограммы:
. ………Наша
задача сформировать из этих подпрограмм перемещаемый ассемблерный
модуль. Учесть, что регистры, с которыми будут работать подпрограммы,
могут оказаться в любых адресах и банках. Сам код подпрограмм также
может быть размещён при компиляции в любых страницах памяти программ. Начало модуля……….Необходимо определить однобайтные переменные e_rez, d_rez, temp. Для этого воспользуемся директивой udata. Кроме того, чтобы основная программа могла получить доступ к переменным e_rez, d_rez, их необходимо сделать глобальными, то есть применить к ним директиву global.……….Итак, начало нашего будущего модуля:
. ………Директива udata объявляет (говорит ассемблеру о начале) секцию переменных. Директива res резервирует место под переменные, то есть транслятор (ассемблер) выделяет столько байт, сколько указано. ……….В нашем случае мы объявили три переменные e_rez, d_rez, temp, под каждую из которых будет выделен один байт памяти. ……….Ассемблер Mpasm может быть использован двумя способами: ……….- для генерации абсолютного кода, который может быть напрямую исполнен микроконтроллером ……….- для генерации перемещаемого кода, который может быть объединён с другими отдельно скомпилированными файлами ……….Мы задействуем его во втором варианте, для объединения нескольких файлов в один проект. ……….Когда файлов в проекте больше одного, то в дело включается линкер. Ассемблер генерирует из каждого АСМ файла объектный файл. Линкер собирает отдельные объектные файлы в цельный проект, пересчитывает адреса размещения кода и адреса меток в коде, а также размещает переменные в RAM области с назначением им конкретных адресов. ……….Почему модуль кода называется перемещаемым? ……….Он может быть размещён линкером в любых адресах памяти программ и работать с регистрами в любых адресах памяти данных микроконтроллера. ……….В объектном файле находится готовый код и информация об используемых данных. Адрес начала этого кода в будущем проекте можем определить заранее или оставить его определение на усмотрение линкера, что обычно и делается. В некоторых случаях необходимо зафиксировать размещение кода. ……….Директива code объявляет начало секции кода и позволяет при необходимости зафиксировать секцию кода в конкретных адресах памяти программ микроконтроллера. ……….Наращиваем «шапку» нашего перемещаемого модуля.
. ………Если бы мы хотели разместить начало кода в определённых адресах памяти, например с адреса 0x0000, то пришлось бы сделать запись:
……….Применяется фиксация адреса в перемещаемом коде в редких случаях. Когда необходимо указать на начало программы, при объявлении начала адреса программы прерывания, размещении загрузчика или таблицы с данными. Фиксирование адреса в перемещаемом коде в других случаях практически не применяется, так как фиксированные адреса могут привести к несовместимости модулей. ……….Каждую секцию кода можно назвать отдельным именем. Впоследствии, если будет необходимость включить подпрограммы в библиотечный файл, это пригодится. Так и сделаем:
. ………Именование секций, подпрограмм, переменных и других элементов при программировании с возможностью повторного использования кода – отдельная тема. Имя подпрограммы должно отражать её функциональное назначение и способствовать тому, чтобы, всего лишь взглянув на имя подпрограммы, модуля или файла, можно было легко вспомнить и понять функциональное назначение кода. Подробнее с правилами оформления кода и именования меток можно ознакомиться в статье: «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.
. ………Постоянное применение директив banksel и bankisel создаёт ту самую избыточность перемещаемого кода, которой обычно удаётся избежать при создании кода абсолютного. Перемещаемый код требует несколько больше места в памяти программ контроллера. Это относится в основном к микроконтроллерам средней серии типа PIC16Fxxx. В 18-й серии и более новых микроконтроллерах Microchip большей разрядности ОЗУ устроено по–другому, и перемещаемый код более компактен. Сборка модуля……….Следующий необходимый шаг – объявить подпрограммы Bin99Dec, Dec99Bin глобальными, чтобы основная программа могла их вызвать. Что происходит при объявлении метки глобальной, вы наверное уже догадались. Ассемблер в объектном файле создаёт таблицу меток, к которым разрешён доступ извне. Если основная программа обращается к глобальной метке внешнего модуля, то всё отлично, доступ разрешён. Если же метка глобальной не является, то доступа к ней нет. При попытке обращения к внутренней метке модуля ассемблер выдаст ошибку, что идентификатор неопределен.……….Это позволяет использовать одинаковые имена меток в разных модулях одного проекта и обеспечивает разделение регистров между модулями. Ячейки, которые глобальными не являются, используются только внутри модуля и к ним нет доступа из других модулей программы………..Для окончательной сборки модуля остаётся добавить в него строку подключения файла определений для микроконтроллера среднего семейства и завершить всё директивой end
Настройка всех модулей проектана один контроллер. ………Если модулей в проекте несколько, то придётся настроить их все на один и тот же тип микроконтроллера. Можно для этого во всех модулях переделать строку:
……….Файл модуля примет вид:
Подключение перемещаемого ассемблерногомодуля к проекту. ………Так как речь идёт о применении в проекте нескольких файлов, то нужно создать ещё один файл – основной файл проекта. Создадим простейшую «пустышку». Для понимания того, как задействовать модули, этого достаточно. Вот код основного файла проекта:
……….Создаём для проекта новую папку и размещаем в неё подготовленные файлы. При сборке и компиляции проекта задействуется линкер, поэтому в папку проекта копируем файл скрипта линкера для микроконтроллера PIC16F628A «16f628a.lkr». ……….Воспользовавшись Project Wizard, создаем новый проект. Первоначально у нас задействовано четыре файла, и окно проекта выглядит так: ……….Жмём кнопку «Build All». Всё компилируется. Проверим, что получилось в памяти программ.
. ………Сразу
видим, что секции кода (подпрограммы Bin99Dec,Dec99Bin и основная
программа) поменялись местами. На будущее нужно учесть, что при
сборке проекта отдельные секции кода могут быть размещены линкером в
любых адресах. Ну, да на то они и перемещаемые. Директива EXTERNЗадействуем модуль в основной программе……….Для того чтобы основной файл смог использовать внешние метки необходимо добавить в него строку:
……….Директива extern даёт понять ассемблеру, что метки, указанные за ней, внешние и находятся в других файлах проекта. Линкеру предстоит найти их при компиляции в других объектных файлах и добавить в таблицу используемых меток основного файла. ……….В первом примере подпрограммы модуля не вызываются, и обращения к ячейкам e_rez, d_rez из основной программы нет. Добавим несколько обращений к программам модуля, усложним немного основную программу.
. ………Так как модуль может оказаться в любой странице памяти программ, при вызове подпрограмм используется встроенный макрос lcall. Макрос lcall перед вызовом подпрограммы настраивает соответствующие биты регистра PCLATH на ту страницу памяти программ, где расположена вызываемая подпрограмма. ……….При возврате из подпрограммы регистр PCLATH восстанавливается макрокомандой pagesel и настраивает биты PCLATH в соответствие с текущей страницей памяти программ.
……….Применение этих команд в перемещаемом коде необходимо и также создаёт некоторую избыточность перемещаемого кода по сравнению с кодом абсолютным. ……….После пошагового прогона скомпилированного проекта в отладчике убеждаемся, что ошибок при преобразовании нет. Модуль готов. Единственное, что может смутить на данном этапе, чтобы основной файл смог обращаться к подпрограммам модуля, в него необходимо добавить строку, в которой определены внешние метки подключенного перемещаемого кода.
……….Допустим мы собрали несколько таких модулей, в каждом решили конкретные задачи и разместили по несколько подпрограмм, каждая из которых работает со своими переменными и решает определённую задачу. Например, в одном модуле все подпрограммы, обеспечивающие связь по USART, в другом решается задача измерения температуры с датчика DS18B20, в третьем — подпрограммы работы с внешней памятью, типа 24Cxx, и т.д. ……….Для каждого из модулей придётся добавить в основной файл проекта строки с определением внешних меток директивой extern. Подключаемый заголовочный файл……….Основной способ, применяемый при подключении модуля к проекту, – использование заголовочного файла.……….Создаём ещё один файл с названием «bin99dec.inc». В этом файле прописываем:
……….В файле фактически дублируется строка:
……….Комментарии позволят разобраться в функциональном назначении модуля, не заглядывая в код самого модуля, только лишь заглянув в заголовочный файл. Кроме того, в заголовочный файл можно включить макроопределения (макросы) и константы, необходимые для работы с модулем. ……….Создав файл «bin99dec.inc», подключаем его к основному проекту при помощи директивы include. ……….Основной файл проекта в этом случае будет выглядеть так:
. ………При компиляции, если модуль подключен к проекту с использованием заголовочного файла, получается тот же результат, что и со строкой объявления внешних меток.
……….Директива include работает по тому же принципу, что и макрос, но в приложении к целому файлу, являясь удобным способом подстановки готового кода всего лишь одной строкой. ……….В окно основного проекта можно добавить файл заголовка, в пункт «Header Files», чтобы можно было одним кликом заглянуть в него при необходимости: Блокировка повторного включениязаголовочных файлов……….Когда модули становятся основным способом программирования, могут возникнуть довольно сложные ситуации, когда один модуль использует подпрограммы другого модуля. Возможно включение в заголовочный файл одного модуля заголовочного файла другого модуля и повтор включенных заголовков. Если произойдёт дублированное включение одного и того же заголовка, то неизбежна ошибка при компиляции:……….«Дублирование меток». ……….Чтобы этого избежать, применяется блокировка повторного включения файла заголовка в один и тот же файл. Для блокировки повторного включения применяются директивы условной компиляции:
……….С помощью этих директив исключается повторное включение заголовка в один тот же файл проекта. Заголовочный файл в нашем примере примет такой вид:
……….Вот и весь принцип построения модулей и подключения их к проектам. Создавать модули несколько сложнее, чем единичный проект. Но выигрыш от такого подхода хорошо осознаётся со временем, когда программ и проектов становится много, и что-то найти в собственных исходниках иногда сложнее, чем переписать весь код по-новой. Готовая собственная библиотека модулей — отличное подспорье, если вы много программируете. ……….Литература: |
Учебный курс. Часть 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.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.
Пример —
Алгоритм —
- Мы берем первый элемент массива в A
- Сравнение A с другими элементами массива, если A меньше, то сохранить этот элемент в A, в противном случае сравнить со следующим элементом
- Значение 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
- LXI 2050 назначает 20 H и 50 L
- MOV C, M копирует содержимое памяти (указанное парой регистров HL) в C (используется как счетчик)
- DCR C уменьшает значение C на 1
- INX H увеличивает значение HL на 1. Это делается для посещения следующей ячейки памяти
- MOV A, M копирует содержимое памяти (заданное парой регистров HL) в A
- INX H увеличивает значение HL на 1. Это делается для посещения следующей ячейки памяти
- CMP M сравнивает A и M, вычитая M из A. Флаг переноса и знак знака устанавливается, если A-M отрицательное
- JNC 200D переводит программный счетчик на 200D, если флаг переноса = 0
- MOV A, M копирует содержимое памяти (заданное парой регистров HL) в A
- DCR C уменьшает значение C на 1
- JNZ 2007 переводит программный счетчик на 2007, если нулевой флаг = 0
- STA 3050 сохраняет значение A в ячейке памяти 3050
- 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
in n
LDR
инструкции.
Настоящие инструкции ARM не позволяют использовать ПК в других целях.
В коде большого пальца вы можете использовать ПК для R
в t
LDR
Word инструкции и ПК для R
in n
LDR
инструкции. Другое использование ПК в этих инструкциях Thumb не разрешено.
Использование SP
Вы можете использовать SP для R
. n
В коде ARM вы можете использовать SP для R
в текстовых инструкциях.Вы
можно использовать SP для t
R
в несловных инструкциях в коде ARM, но это
устарела в ARMv6T2 и более поздних версиях. t
В коде большого пальца вы можете использовать SP для R
в текстовых инструкциях
только. Любое другое использование SP для t
R
в этой инструкции не
разрешено в коде Thumb. t
Примеры
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 | Демократ | Связаться с членом Ассамблеи Сесилией М. Агияр-КарриОфис Капитолия, комната 5144P.O. Box 942849, Sacramento, CA 94249-0004; (916) 319-2004 editDistrict Office 600 A Street, Suite D, Davis, CA 95616; (530) 757-1034 edit Добавить офис |
Арамбула, д-р.Хоакин [править] | 31 | Демократ | Связаться с членом Ассамблеи доктором Хоакином АрамбулаОфис Капитолия, комната 5155P. O. Box 942849, Sacramento, CA 94249-0031; (916) 319-2031 editDistrict Office 2550 Mariposa Mall, Room 5031, Fresno, CA 93721; (559) 445-5532 редактировать Добавить офис |
Бауэр-Кахан, Ребекка [править] | 16 | Демократ | Связаться с членом Ассамблеи Ребеккой Бауэр-КаханCapitol Office, Room 2130P.О. Box 942849, Сакраменто, Калифорния 94249-0016; (916) 319-2016 editDistrict Office 2440 Camino Ramon, Suite 345, San Ramon, CA 94583; (925) 328-1515 редактировать Добавить офис |
Беннет, Стив [править] | 37 | Демократ | Свяжитесь с членом Ассамблеи Стивом Беннеттом,, Офис Капитолия, комната 6031P. О. Box 942849, Сакраменто, Калифорния 94249-0037; (916) 319-2037 editDistrict Office 101 West Anapamu Street, Suite A, Santa Barbara, CA 93101; (805) 564-1649 edit Добавить офис |
Берман, Марк [править] | 24 | Демократ | Связаться с членом Ассамблеи Марком БерманомCapitol Office, Room 6011P.О. Box 942849, Сакраменто, Калифорния 94249-0024; (916) 319-2024 editDistrict 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 editDistrict Office 730 North I Street, Suite 102, Madera, CA 93637; (559) 673-0501 edit Добавить офис |
Блум, Ричард [править] | 50 | Демократ | Связаться с членом Ассамблеи Ричардом БлумомОфис Капитолия, комната 2003P.О. Box 942849, Сакраменто, Калифорния 94249-0050; (916) 319-2050 editDistrict Office 2800 28th Street, Suite 105, Santa Monica, CA Добавить офис |
Бурнер Хорват, Таша [править] | 76 | Демократ | Связаться с членом Ассамблеи Ташей Боернер ХорватКапитолий Офис, комната 4130P. О. Box 942849, Сакраменто, Калифорния 94249-0076; (916) 319-2076 редактироватьРайонный офис 325 Carlsbad Village Drive, Suite A-2, Carlsbad, CA 92008; (760) 434-7605 редактировать Добавить офис |
Бонта, Роб [править] | 18 | Демократ | Связаться с членом Ассамблеи Роба БонтаCapitol Office, комната 2148P.О. Box 942849, Сакраменто, Калифорния 94249-0018; (916) 319-2018 editDistrict Office 1515 Clay Street, Suite 2204, Oakland, CA 94612; (510) 286-1670 редактировать Добавить офис |
Берк, Отэм Р. [править] | 62 | Демократ | Связаться с членом Ассамблеи Отем Р. BurkeCapitol Office, комната 5150P.O. Box 942849, Sacramento, CA 94249-0062; (916) 319-2062 редактироватьОкружной офис One Manchester Boulevard, Suite 601, Inglewood, CA ; (310) 412-6400 редактировать Добавить офис |
Кальдерон, Лиза [править] | 57 | Демократ | Связаться с членом Ассамблеи Лизой КальдеронCapitol Office, Room 2175P.О. Box 942849, Сакраменто, Калифорния 94249-0057; (916) 319-2057 редактироватьРайонный офис 13181 Crossroads Parkway North, Suite 160, City of Industry, CA 91746-3497; (562) 692-5858 редактировать Добавить офис |
Каррильо, Венди [править] | 51 | Демократ | Свяжитесь с членом Ассамблеи Венди Каррильо,, Офис Капитолия, комната 4167P. |