Краткое описание распространенных в разное время процессоров

Для дальнейшего изложения касающегося языков программирования и компиляторов необходимы опpеделенные сведения об устройстве вычислительной машины и системе команд. Если они Вам известны, этот pаздел можно пpопустить. В первоначальном варианте этого текста (Машинный код и язык ассемблера) рассматривался только устаревший процессор Intel 8086. Он (текст) был написан когда уже существовали процессоры 80486 и Pentium, но часто они использовались просто как быстродействующие 8086.

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

Для проверки использовались реальные машины и/или программные эмуляторы - не все рассмотренные здесь системы доступны.

В ряде случаев вместо общего формата команды приводится несколько частных вариантов, обычно это оговаривается. Большая часть этих вариантов соответствует командам процессора 8080, по-видимому самого простого из рассматриваемых.

Скорее всего, описание неполное, сложно ничего не упустить в малом объеме. Для сравнения только один документ "AMD64 Architecture Programmer’s Manual Volume 3: General Purpose and System Instructions" (Revision 3.20, май 2013) имеет объем 610 страниц. Так что все стало сложнее...

Однажды мне в руки попала книжка Т. Мартина "Физические основы электротехники". Она ничинается так.

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

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

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

Здесь нужно упомянуть о микросхемах FPGA (Field-programmable gate array) и CPLD (Complex programmable logic device). С их помощью можно самостоятельно реализовать процессор, причем, если ограничиться немногим это довольно просто. Наверное, это существенно не равно разработке процессора на простых логических микросхемах и тем более, на дискретных элементах, но все же это нечто большее, чем написание программного эмулятора.

Насколько я понял, FPGA отличаются от CPLD только числом элементов (в FPGA их больше) и способом хранения конфигурации (соответственно, в статической и flash-памяти). По-видимому, FPGA предпочтительнее - они содержат больше элементов и не имеют ограничения на число циклов записи конфигурации. Если верить документации, микросхемы CPLD Altera MAX II EPM240/570/1270 допускают всего сто циклов записи, но встечаются утверждения, что в реальности все не настолько плохо.

Для удобства сравнения описание каждого из процессоров будет распределено по перечисленным ниже разделам. В настоящее время закончены схемы регистров и описания процессоров EDSAC, IBM 701, IBM 704, IBM System/360, PDP-11, Intel 4004, Intel/AMD (8080, 8086, i386 и Athlon64), MOS6502, микроконтроллеров 8051, PIC10/12/16, AVR и ARM, а также схемы регистров некоторых других процессоров. Для одной страницы очень много:)

Если нужна информация по какому-то одному процессору, имеет смысл в двух дополнительных окнах открыть соответсвующие части разделов Логическое устройство и Форматы команд.

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

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

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

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

Мы привыкли к тому, что машины работают с восьмибитными байтами и словами, состоящими из двух, четырех или восьми байт. Числа с плавающей точкой размещаются в четырех или восьми байтах и содержат знак, мантиссу и порядок. Так было не всегда. В первых машинах регистры содержали больше восьми бит (17, 36, 48, 60 бит и вряд ли это все варианты). Для представления (естественно, приближенного) вещественных чисел использовались форматы с фиксированной точкой. Байт по-видмому появился в машинах IBM System/360, но это неточно.

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

Реальные системы обычно сложнее, в них исполняемая программа может прерываться при наступлении тех или иных событий (например, при нажатии клавиши на клавиатуре или изменении показаний часов), работать с оперативной памятью могут и другие устройства (например, контроллеры дисковых накопителей могут записывать данные в память или читать их из памяти их без участия процессора, это нужно для увеличения скорости передачи и исключения потерь данных). Наконец, процессор может быть не один. Тем не менее до сих пор (2017 год) выпускаются системы точно соответствующие указанной простой модели выборки/выполнения, например, микроконтроллеры PIC10F200. Эта же микросхема является примером системы без оперативной памяти - имеются только 16 регистров.

Команды можно pазделить на тpи гpуппы:

Могут существовать комбиниpованные команды, напpимеp извлечение числа из памяти и сложение его с дpугим числом, находящимся в pегистpе.

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

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

  A - B = A + (2^N - 1) - B - (2^N - 1) = A + (((2^N - 1) - B) + 1) - 2^N = A + (!B + 1) - 2^N

Здесь N - число разрядов сумматора, а (2^N - 1) - число содержащее единицы во всех разрядах, при вычитании из него любого другого числа не нужно выполнять заем. Число

  !B + 1

и есть дополнительный код числа B. Если A больше или равно B, сумма A и дополнительного кода B будет не меньше 2^N, и чтобы вычесть из нее 2^N нужно просто отбросить перенос из старшего разряда. Если же A меньше B, переноса из старшего разряда не будет и это означает, что результат вычитания не может быть представлен (нигде выше отрицательные числа не предполагались).

Дополнительный код был использован для замены вычитания комбинацией отрицания и сложения (т.е. для исключения из арифметического устройства отдельной схемы вычитания), но он же может служить и для представления отрицательных чисел. Если число B отрицательно, оно представляется "положительным" числом

  !|B| + 1

Половина чисел (от 0 до 2^(N - 1) - 1) считаются неотрицательными, оставшаяся половина (от 2^(N - 1) до 2^N - 1) отрицательными. Перебрав все варианты (их немного) можно убедиться, что если результат сложения и вычитания неотрицаелен и он находится в указанном выше диапазоне, он и окажется на выходе сумматора. Если же результат отрицателен и также находится в указанном выше диапазоне отрицательных чисел, на выходе сумматора окажется его дополнительный код. Факт переполнения может быть зафиксирован, об этом немного ниже.

Модуль наименьшего допустимого отрицательного числа превышает на единицу наибольшее допустимое положительное число.

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

C Устанавливается, если при сложении или вычитании произошел перенос из старшего разряда
V Устанавливается, если при сложении или вычитании произошло знаковое переполнение
Z Устанавливается, если результат равен нулю
N Устанавливается, если результат отрицателен (т.е. старший разряд результата содержит единицу)

Правила установки признаков C, Z и N тривиальны (но одни процессоры при выполнении вычитания инвертируют признак C, а другие этого не делают), признак V устанавливается если имел место перенос в старший разряд и не имел места перенос из старшего разряда или, наоборот, если не имел места перенос в старший разряд и имел место перенос из старшего разряда. Это неочевидно, но именно это позволяет корректно выполнить сравнение чисел, имеющих разные знаки. Если эти числа достаточно велики, при вычитании произойдет переполнение и знаковый разряд будет искажен. Проблему можно было бы решить, добавив еще один разряд в сумматор, но это потребовало бы большего числа элементов, чем для схемы несовпадения.

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

  {A} + !{B} + 1 = A + !(2^N - |B|) + 1 = A + ((2^N - 1) - (2^N - |B|)) + 1 = A + |B|

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

В соответствии с этой формулой сумматор складывает представление A и инверсный код представления B, причем на вход переноса младшего разряда сумматора подается единица.

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

Остальные три случая рассматриваются аналогичным образом. Если знаки операндов совпадают, переполнение не происходит и значение признака знака корректно. Условия переходов на основании сравнения чисел со знаком содержат два признака - N и V. Рассмотрев все четыре комбинации знаков несложно доказать эквивалентность условий:

  (A <  B) <=> (N != V)
  (A >= B) <=> (N  = V)

Если числа предполагаются неотрицательными, результат вычитания определяется формулой:

  {A} + !{B} + 1 = A + ((2^N - 1) - B) + 1 = 2^N + (A - B)

Если уменьшаемое A больше или равно вычитаемому B, произойдет перенос из старшего разряда. Если A меньше B, переноса не будет. Одни (многие?) процессоры в этом случае инвертируют признак C, другие этого не делают. Процессоры 80x86 инвертируют признак C, MOS6502 нет.

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

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

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

В pаботе вычислительной машины важную pоль игpает стек. Это область опеpативной памяти, адресуемая указателем стека (SP - Stack Pointer), для работы с ней предназначены команды помещения в стек (push) и извлечения из него (pop). Стек можно пpедставлять как стопку книг - вы кладете новую книгу на уже лежащие и можете взять лишь веpхнюю из них. Для полного сходства стопка должна лежать на потолке (обычно, но не всегда, максимально возможное значение SP соответствует пустому стеку):

 
 
 
SP-> 
 
 
 
0 ->
  USED  
  USED  
  USED  
  USED  
        
        
        
        

Если направить ось адресов вниз, стопка книг будет находиться на дне колодца:

0 ->
 
 
 
SP-> 
 
 
 
        
        
        
        
  USED  
  USED  
  USED  
  USED  

Стек используется для оpганизации вызова подпpогpамм и для хpанения пpомежуточных pезультатов вычислений. В некоторых простых системах стек может использоваться только для оpганизации вызова подпpогpамм. В IBM System/360 аппаратная поддержка стека вообще отсутствует, но это не значит, что его нельзя организовать.

Логическое устройство

Pascal-S

   SP   
   DP   
   IP   
Стековая машина. Содержит оперативную память и три регистра - указатель стека SP, указатель на начало глобальных данных DP и указатель команды. Объем памяти, разрядность ее ячейки и разрядность регистров могут быть различны. Без регистра DP в принципе можно обойтись, память может разделена на память программы и память данных - как в микроконтроллерах.

Регистры данных также есть, но они используются только исполняющей системой. Программисту они недоступны.

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

Была реализована Н.Виртом в виде программы Pascal-S, представляющей собой компилятор подмножества языка Pascal и собственно стековую машину.

EDSAC

 SCT                                  
        MR                           
        MD                           
                  AC                  
EDSAC - Electronic Delay Storage Automatic Calculator. Первый(?) электронный компьютер. Может обращаться к оперативной памяти объемом 1024 семнадцатиразрядных слов, также возможно обращение и работа с двойными словами. Числа могут расссмативаться как целые или как дробные в диапазоне от -1 до 1 - 2-(N-1) (N - число разрядов слова), никих чисел с плавающей точкой нет. Может выполнять умножение, а деление - нет. При умножении числа считаются дробными, для перемножения целых нужно дополнительно сдвигать результат влево.

Содержит семидесятиодноразрядный регистр-аккумулятор AC, два тридцатипятиразрядных регистра - множитель MR (multiplier) и множимое MD (multiplicand), десятиразрядный указатель исполняемой инструкции SCT (sequence control tank). Слово tank использовано, поскольку для реализации регистров (и памяти) использовались акустические линии задержки (acousyic delay lines) - трубки со ртутью, на концах которых были установлены пьезоэлектрические преобразователи - излучатель и микрофон. Обращение к такой памяти только последовательное (т.е. за один раз можно записать или прочитать только один бит и только в подходящий момент времени). Текущие значения в регистрах и выбранной трубке памяти можно было видеть на экранах осциллографов.

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

Подлежащая исполнению программа считывается загрузчиком с пятидорожечной перфоленты, длина команды на ленте переменная. В документации команда нызывается order, но это же слово используется и для обозначения последовательности команд, в частности загрузчика, который называется Initial Order. Загрузчиков было два - простой Initial Order 1 и "расширенный" Initial Order 2.

Существует программный симулятор). По умолчанию в ней используется загрузчик Initial Order 2, если нужен Initial Order 1, его нужно выбрать.

IBM 701

         AC        
          MQ        
    IC               
Тридцатишестиразрядный процессор 701 фирмы IBM. Может обращаться к оперативной памяти объемом 2048 тридцатишестиразрядных слов. Содержит тридцативосьмиразрядный регистр-аккумулятор AC (знаковый бит S, два бита переполнения P и Q, тридцатипятиразрядное значение), тридцатишестиразрядный регистр множителя/частного (multiplier/quitient register), двенадцатиразрядный указатель инструкции IC. Возможен доступ к половинам слов. Длина команды - восемнадцать бит (половина слова).

IBM 704

         AC         
          MQ        
    A                
    B                
    C                
   ILC               
Тридцатишестиразрядный процессор 704 фирмы IBM. Относится к той же серии, что и IBM 701, но значительно отличается. Может обращаться к оперативной памяти объемом 4096, 8192 или 32768 тридцатишестиразрядных слов. Содержит тридцативосьмиразрядный регистр-аккумулятор AC (знаковый бит S, два бита переполнения P и Q, тридцатипятиразрядное значение), тридцатишестиразрядный регистр множителя/частного (multiplier/quitient register), три (по другим данным семь) индексных регистра A, B и C и указатель инструкции ILC. Длина индексных регистров двенадцать, тринадцать или пятнадцать бит (в зависимости от установленного объема оперативной памяти) - даже на такой мелочи экономили. Длина команды - тридцать шесть бит, аппаратно реализована арифметика с плавающей точкой (одинарной точности?). В отличие от IBM 701 есть возможность косвенного обращения к памяти, для чего и были предназначены индексные регистры.

IBM System/360

       R0               R1       
       R2               R3       
       R4               R5       
       R6               R7       
       R8               R9       
       R10              R11      
       R12              R13      
       R14              R15      
               PSW              
Тридцатидвухразрядный процессор фирмы IBM, применявшийся в ряде вычислительных машин серии 360. Может обращаться к оперативной памяти объемом до шестнадцати мегабайт. Содержит шестнадцать универсальных тридцатидвухразрядных регистров и шестидесятичерырехразрядный регистр PSW, состоящий из двадцатичетырехразрядного адреса инструкции (младшие биты 40..63, при счете справа налево 23..0) и ряда других полей. Старшие модели также содержат четыре шестидесятичерырехразрядных регистра для хранения операндов с плавающей точкой, на схеме они не показаны.

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

Отсутствует аппаратная поддержка стека(?).

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

PDP-11

   R0   
   R1   
   R2   
   R3   
   R4   
   R5   
 SP(R6) 
 PC(R7) 
 
   PS   
Шестнадцатиразрядный процессор машины PDP-11 фирмы DEC. Может обращаться к оперативной памяти объемом до шестидесяти четырех килобайт (в старших моделях объем памяти мог достигать четырех мегабайт, но в каждый момент времени была доступна лишь одна шестидесятичетырехкилобайтная страница?). Содержит шесть универсальных шестнадцатиразрядных регистров, шестнадцатиразрядные указатель стека SP(R6), программный счетчик PC(R7) и регистр состояния PS.

4004

 0  1   PC  
 2  3   L1  
 4  5   L2  
 6  7   L3  
 8  9
10 11
12 13
14 15
AC
Четырехразрядный микропроцессор фирмы Intel. Использовался в калькуляторе Busicom 141-PF, но не только в нем. Собственно микропроцессор 4004 не содержит всех необходимых схем, для его работы нужны специализированные микросхемы 4001 (ПЗУ объемом 256 байт) и 4002(4002-1, 4002-2 - ОЗУ объемом 80 полубайт, отличаюшиеся логикой выбора кристалла). Доступ к 64 из 80 полубайт реализован "обычным" образом, для доступа к оставшимя 16 полубайтам используются специальные команды. Помимо собственно памяти эти микросхемы содержат регистр адреса, порт ввода-вывода (4001, 4002 - порт только вывода) и необходимую логику. Обращение к памяти требует в общем случае трех команд - выбора банка памяти, выбора ячейки и собственно обращения (чтения или записи).

В комплект также входит сдвиговый регистр 4003, предназначенный для увеличения числа портов ввода-вывода. Все микросхемы выпускались корпусах с шестнадцатью выводами. Для передачи адресов и данных используется четырехразрядная шина, еще пять выводов предназначены для управления работой микросхем памяти. Без использования дополнительных микросхем можно построить систему, содержащую 16 микросхем ПЗУ 4001 и 16 микросхем ОЗУ 4002 (четыре банка из двух 4002-1 и двух 4002-2). Такая система больше похожа микроконтроллер, точнее микроконтроллер похож на нее.

Микропроцессор содержит четырехразрядный регистр-аккумулятор AC, результат многих операций может помещаться только в него, шестнадцать четырехразрядных регистров 0-15, двенадцатиразрядный счетчик команд PC и трехуровнеый стек L1-L3, предназначенный только для хранения адресов возврата из подпрограмм.

Также имеются программно недоступный указатель стека и два одноразрядных регистра флагов (флаг переноса/заема CY и флаг TEST, связанный со входом тестового сигнала), на схеме они не показаны.

При выполнении ряда операций пары соседних регистров ([0, 1]-[14, 15]) используются совместно. В частности, имеются команды загрузки восьмиразрядной константы в пару регистров.

Упомянутый калькулятор Busicom 141-PF по нынешним меркам очень сложен. Помимо микропроцессора 4004 он содержит черыре микросхемы ПЗУ 4001, две микросхемы ОЗУ 4002, три сдвиговых регистра 4003 и много других элементов.

8080

 A    B    C  
 D    E  
 H    L  
   PC   
   SP   
 PSW
Восьмиразрядный микропроцессор фирмы Intel. Может обращаться к оперативной памяти объемом до шестидесяти четырех килобайт. Содержит восьмиразрядные регистр-аккумулятор A, результат многих операций может помещаться только в него, шесть регистров данных B, C, D, E, H, L, регистр состояния PSW и шестнадцатиразрядные указатель команды PC и указатель стека SP.

При выполнении ряда операций регистры данных объединяются в пары BC, DE и HL. Помимо команд обработки байтов есть несколько команд обработки шестнадцатиразрядных слов.

В ряде распространееных домашних компьютеров использовался усовершенствованный клон 8080 - процессор Z80 фирмы Zilog.

6800

 A      PC   
 B      SP   
   IX   
 PSW
Восьмиразрядный микропроцессор фирмы Motorola.

6502

 A      PC   
 S       
 X  
 Y  
 P  
Восьмиразрядный микропроцессор фирмы MOS Technologies. Может обращаться к оперативной памяти объемом до шестидесяти четырех килобайт. Содержит восьмиразрядные регистр-аккумулятор A, регистры данных/индексов X и Y, регистр состояния P, указатеть стека S и единственный шестнадцатиразрядные регистр - указатель команды PC.

Шестнадцатиразрядные индексные регистры отсутствуют, для косвенных обращений к оперативной памяти используются пары соседних ячеек памяти с адресами от 0x0000 до 0x00FE, значения в которых используются как адреса. Имеются короткие (2 байта) команды для обращений к памяти с адресами от 0x0000 до 0x00FF. Область памяти с адресами от 0x0100 до 0x01FF используется как стек (к значению S неявно прибавляется смещение 0x0100).

Применялся в ранних компьютерах фирмы Apple и игровых приставках Nintendo.

[8000]

 A    B    C  
 D      SP   
   PC   
 PSW
Вымышленный восьмиразрядный процессор, рассматриваемый в книге Ч.Гилмора "Введение в микропроцессорную технику". Содержит восьмиразрядные регистр-аккумулятор A, результат операций может помещаться только в него, три регистра данных B, C, D, регистр состояния PSW и шестнадцатиразрядные указатель стека SP и указатель команды PC. Пара регистров BC может использоваться как шестнадцатиразрядный индексный регистр.

8086

   AX       IP       CS   
   BX       SP       SS   
   CX       SI       DS   
   DX       DI       ES   
   BP   
   PSW  
Шестнадцатиразрядный микропроцессор фирмы Intel. Может обращаться к оперативной памяти объемом до одного мегабайта. Содержит четыре регистра данных AX, BX, CX и DX, регистр состояния PSW, указатели команды IP, указатель стека SP, два индексных регистра SI и DI, указатель базы BP и четыре сегментных регистра CS, SS, DS и ES. Все регистры шестнадцатиразрядные.

Регистры данных состоят из пар восьмиразрядных регистров AH, AL, BH, BL, CH, CL, DH и DL, которые могут использоваться независимо. Регистр BX может использоваться как индекс и как база. Индексные регистры могут использоваться как шестнадцатиразрядные регистры данных.

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

Пары регистров CS:IP и SS:SP используются совместно.

К1801ВМ1

   R0   
   R1   
   R2   
   R3   
   R4   
   R5   
 SP(R6) 
 PC(R7) 
 
   PS   
Процессор К1801ВМ1. Интегральный аналог шестнадцатиразрядной мини-ЭВМ PDP-11 фирмы DEC. Применялся в бытовом компьютере БК-0010.

68000

       D0               A0       
       D1               A1       
       D2               A2       
       D3               A3       
       D4               A4       
       D5               A5       
       D6               A6       
       D7               USP      
       PC       
            CCR  
Тридцатидвухразрядный микропроцессор фирмы Motorola. Применялся в ранних компьютерах Apple Macintosh и игровых приставках Nintendo.

i386

       EAX              EIP          CS   
       EBX              ESP          SS   
       ECX              ESI          DS   
       EDX              EDI          ES   
       EBP          FS   
   GS   
       PSW      
Тридцатидвухразрядный микропроцессор фирмы Intel. Расширение архитектуры 8086, разрядность регистров данных и индекных регистров увеличена вдвое. Может обращаться к оперативной памяти объемом до четырех гигабайт, имеет встроенные механизмы преобразования адресов памяти, обеспечивающие представление множества несвязных областей памяти как одной связной и защиту от ошибочных обращений.

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

По сравнению с 8086 адрес обращения к памяти формируется более сложным образом. Сначала сложением значения в базовом регистре со значением в индексном регистре (возможно, умноженным на масштабный коэффициет 2, 4 или 8) и с восьми- или тридцатидвухразрядным смещенем, являющимся частью команды, формируется логический адрес. Два из трех элементов адреса могут отсутствовать, использование одного регистра EBP невозможно. Затем сложением логического адреса с начальным адресом сегмента формируется линейный адрес. Если режим страничной трасляции выключен, физический адрес равен линейному. Иначе линейный адрес рассматривается как набор из трех полей - смещения в каталоге таблиц страниц (10 бит), смещения в таблице страниц (10 бит) и смещения в странице памяти (12 бит), эти таблицы также заполняются операционной системой. Обращение к каталогу таблиц страниц дает адрес таблицы страниц, обращение к ней - адрес страницы, сумма этого адреса и смещения дает физический адрес.

Прикладная программа никак не может повлиять на эти преобразования. Адреса указанных таблиц хранятся в специальных регистрах GDTR, IDTR и CR3. В регистре LDRT хранится идекс элемента таблицы дескрипторов, содержащего адрес локальной таблицы дескрипторов. Эти регистры не показаны на схеме, прикладная программа не может изменить значения в них.

Athlon64

               RAX                              RIP                  CS   
               RBX                              RSP              
               RCX                              RSI              
               RDX                              RDI              
               R8                               RBP                  FS   
               R9                   GS   
               R10              
               R11              
               R12              
               R13              
               R14              
               R15              
                                
               PSW              
Шестидесятичетырехразрядный микропроцессор фирмы AMD. Расширение архитектуры i386, разрядность регистров данных и индекных регистров увеличена еще вдвое, однако, из 64 разрядов адреса используется 48, число линий адреса может быть меньше (40?).

Назначение сегментных регистров опять изменено, как и механизм преобразования адресов. Логический адрес рассматривается как набор из пяти полей - четырех девятиразрядных индексов в таблицах преобразования и двенадцатиразрядного смещения.

8051

 
SFRs
 
 
RAM 
 
 
BITs
 
 
RB3 
 
 
RB2 
 
 
RB1 
 
 
RB0 
 
Восьмиразрядный микроконтроллер фирмы Intel. Несмотря на некоторое сходство обозачений от 8080 отличается очень значительно. Содержит память программ объемом до 8 килобайт(?)(не все модели), четыре банка по восемь регистров (R0-R7), набор регистров специальных функций (SFR) и память данных, состояшую из 96 восьмиразрядных ячеек памяти (16 ячеек BITS и 80 ячеек RAM). Некоторые модели содержат дополнительные 128 восьмиразрядных ячеек памяти. В число SFR входят счетчик команд PCH:PCL, регистр-указатель данных DPTR(DPH:DPL), указатель стека SP, слово состояния PSW, регистр-аккумулятор A и регистр-расширение аккумулятора B. Существуют команды для работы с отдельными битами ячеек BITS и некоторых из SFR. К регистрам и портам можно обращаться как ячейкам оперативной памяти. Возможно подключение внешней памяти программ и данных (не ко всем моделям).

PIC10/12/16

 
GPRs
 
 
GPRs
 
...  ... 
FSR  FSR 
STAT STAT
PCL  PCL  PCH*
TMR0 OPT 
IND* IND*
WREG
 
 STACK 
 
Семейство восьмиразрядных микроконтроллеров фирмы Microchip. Содержат память программ от 256(?) до 16384(?) слов (двенадцати- или четырнадцатиразрядных), от 16(!) до 2048 регистров и портов ввода/вывода, размещаемых в нескольких банках (до восьми) и рабочий регистр WREG. Это не аналог регистра-аккумулятора, в ряде команд он используется только как место хранения одного из операндов. Результат же может записываеться в другой регистр. Обращение к регистрам возможно прямое (по номеру в коде команды) или косвенное (по номеру, записанному в регистр FSR, в команде указывается псевдорегистр IND). Память данных отсутствует, или, другими словами, регистры - это и есть память данных. Для хранения адресов возврата из подпрограмм имеется небольшой стек (в некоторых моделях его емкость всего два слова).

Число команд невелико, например PIC10F200 может выполнять всего 33 различные команды. В документации их перечисление занимает одну страницу, описание занимает еще шесть страниц. В порядке исключения здесь также приведены все команды PIC10.

Число моделей контроллеров очень велико, так что приведенные цифры могут быть неточны. Семейство контроллеров PIC18 имеет несколько большие возможности, более современное семейство шестнадцатиразрядных контроллеров PIC24 и dsPIC существенно отличается. Тридцатидвухразрядные микроконтроллеры PIC32 также отличаются, это представители архитектуры MIPS.

AVR

 
RAM 
 
 
IORs
 
 
REGs
 
    
   PC   
Семейство восьмиразрядных микроконтроллеров фирмы Atmel. Содержат память программ объемом до 8 мегабайт (реально существующий контроллер ATmega2560 содержит 256 килобайт памяти), 32 регистра данных (три пары из которых - R27:R26, R29:28 и R31:30 могут использоваться как индексы), набор регистров (портов) ввода-вывода и память объемом до 8 килобайт(?). Указатель стека SPH:SPL и регистр состояния SREG размещены среди портов ввода-вывода. К регистрам и портам можно обращаться как ячейкам оперативной памяти.

[8001]

 A    B    C  
 D    E  
 H    L  
 F    S  
   IP   
Вымышленный восьмиразрядный микроконтроллер. Все команды имеют длину 1 байт, соответственно все обращения к памяти, все переходы и все вызовы подпрограмм только косвенные, в качестве индекса используется пара регистров HL. Число команд меньше 30. Плотность кода раза в два-два с половиной ниже чем у 8080. Регистр флагов F содержит только флаг переноса. Указатель стека S восьмиразрядный, сам стек размещается в младших 256 байтах памяти данных. Реализация на FPGA Altera Cyclone IV использует менее 400 ячеек (LE). Контроллер был задуман, чтобы разобраться с FPGA.

ARM

       R0       
       R1       
       R2       
       R3       
       R4       
       R5       
       R6       
       R7       
       R8       
       R9       
       R10      
       R11      
       R12      
     R13(SP)    
     R14(LR)    
     R15(PC)    
      APSR      
Множество семейств тридцатидвухразрядных микропроцессоров и микроконтроллеров, разработанных фирмой ARM. Выпускаются разными производителями. Регистр APSR (Appication Program Status Register) содержит как минимум четыре флага (N, Z, C, V) - (Знак, Ноль, Перенос, Переполнение). Помимо показанных на схеме, процессоры содержат/могут содержать ряд других регистров, в т.ч. регистры для вычислений с плавающей точкой. Поддерживают различные наборы команд - ARM (тридцатидвухразрядные команды), Thumb (шестнадцатиразрядные команды), Thumb-2 (тридцатидвухразрядные и шестнадцатиразрядные команды). В процессе работы возможна смена используемого набора команд, но микроконтроллеры ARM этой возможности лишены (?) и поддерживают только набор команд Thumb (и может быть Thumb-2).

MIPS

    $0 /$zero   
    $1 /$at     
    $2 /$v0     
    $3 /$v1     
    $4 /$a0     
    $5 /$a1     
    $6 /$a2     
    $7 /$a3     
    $8 /$t0     
    $9 /$t1     
    $10/$t2     
    $11/$t3     
    $12/$t4     
    $13/$t5     
    $14/$t6     
    $15/$t7     
    $16/$s0     
    $17/$s1     
    $18/$s2     
    $19/$s3     
    $20/$s4     
    $21/$s5     
    $22/$s6     
    $23/$s7     
    $24/$t8     
    $25/$t9     
    $26/$k0     
    $27/$k1     
    $28/$gp     
    $29/$sp     
    $30/$fp     
    $31/$ra     
       pc       
       hi       
       lo       
Тридцатидвухразрядные микропроцессоры и микроконтроллеры, разработанные фирмой MIPS Computer Systems. Помимо показанных на схеме, процессоры содержат/могут содержать регистры для обработки исключений и для вычислений с плавающей точкой. За некоторыми исключениями регистры $1-$31 могут быть использованы произвольно (но есть рекомендации относительно их использования), регистр $0 содержит ноль, pc - указатель команды, в регистры hi и lo записываются результаты умножения и деления. Отсутствуют команды для работы со стеком. Отсутствует регистр флагов. Все команды тридцатидвухразрядные.

Форматы команд

IBM System/360

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

При выполнении арифметических и логических операций модифицируется поле прзнаков PSW (Condition Code, CC, биты 34..35, при счете справа налево 29..28), способ модификации зависит от команды. Например, в результате "обычного" вычитания (S) поле признаков может иметь значение 0 (результат равен нулю), 1 (результат отрицателен), 2 (результат положителен) и 3 (переполнение). В результате "логического" вычитания (SL) поле признаков может иметь значение 0 (результат равен нулю, переноса не было), 1 (результат не равен нулю, переноса не было), 2 (результат равен нулю, перенос был) и 3 (результат не равен нулю, перенос был). В последнем случае можно считать, что CC состоит из битов переноса и не-нуля. Команды переходов содержат четырехбитовое поле MASK, каждый разряд которого соответствует одному из четырех возможных значений CC. Переход выполняется если соответствующий значению CC разряд MASK содержит единицу. Соответствие следующее:

ZMPO - Zero - Minus - Plus - Overflow

или

ELHO - Equal - Low - High - Overflow

Разряды нумеруются справо налево, так что переходу при нулевом результате соответствует 1000, переходу при переполнении 0001. Переходу при ненулевом результате соответствует 0111, безусловному переходу - 1111.

PDP-11

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

Регистр определяется номером от 0 до 7, регистры 0-5 предназначены для хранения данных или адресов, регистр 6 - указатель стека, регистр 7 - программный счетчик.

Операнд может быть указан одним из восьми способов:

  BBB  
R 000 Операнд находится в регистре
(R) 001 Адрес операнда находится в регистре
(R)+ 010 Адрес операнда находится в регистре, после выборки операнда значение в регистре увеличивается на длину операнда в байтах
@(R)+ 011 Адрес адреса операнда находится в регистре, после выборки операнда значение в регистре увеличивается на два
-(R) 100 Значение в регистре уменьшается на на длину операнда в байтах, после чего используется как адрес операнда
@-(R) 101 Значение в регистре уменьшается на два, после чего используется как адрес адреса операнда
Addr(R) 110 Адрес операнда является суммой константы и значения в регистре
@Addr(R) 111 Адрес адреса операнда является суммой константы и значения в регистре

Некоторые варианты не имеют точных аналогов в процессорах Intel/AMD и их назначение может быть неясно, но определенная логика и универсальность здесь есть. Например, способ адресации (R)+ в сочетании с регистром R7 используется для загрузки константы. После считывания первого слова команды (кода операции) значение в R7 увеличивается на 2 и он указывает на следующую за кодом операции константу. Она считывается и значение в R7 увеличивается еще на 2. Этот же способ адресации совместно с регистром R6 используется для извлечения слова из стека. Он же может использоваться совместно с другими регистрами. За счет этого возможно объединение обращения к элементу массива и увеличения значения индекса этого массива. А это уже оператор ++ языка C (правда, только постфиксный). Для префиксного оператора -- также есть аппаратная поддержка.

Коды условий переходов:

    --COND--    
r 00000001 - Без условия
ne 00000010 Z=0 Результат не равен нулю
eq 00000011 Z=1 Результат равен нулю
ge 00000100 N=V Больше или равно, слова больше и меньше предполагают сравнение чисел со знаком
lt 00000101 N!=V Меньше
gt 00000110 N=V & Z=0 Больше
le 00000111 N!=V | Z=1 Меньше или равно
pl 10000000 N=0 Результат положителен
mi 10000001 N=1 Результат отрицателен
hi 10000010 C=0 & Z=0 Выше, слова ниже и выше предполагают сравнение чисел без знака
los 10000011 C=1 | Z=1 Ниже или равно
vc 10000100 V=0 Переполнение не произошло
vs 10000101 V=1 Переполнение произошло
cc/his 10000110 C=0 Перенос не установлен/выше или равно
cs/lo 10000111 C=1 Перенос установлен/ниже

4004

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

Условия перехода связаны со значением флага переноса CY, нулевым или ненулевым значением аккумулятора (флага нулевого результата нет), значением на входе тестового сигнала TEST или некоторыми их комбинациями.

8080

Команды состоят из одного, двух или трех байт, первый байт содержит код операции и, возможно, трехбитовые поля (или дополненное до трех двухбитовое), определяющие регистр-приемник (DST), регистр-источник (SRC), пару регистров (RP) или условие перехода (CCC), соответствующее значению одного из битов регистра состояния PSW (C - перенос, P - четность, Z - ноль, S - знак) - их значения устанавливаются при выполнении арифметических и логических операций. Флаг переполнения отсутствует.

    DST
SRC
 A  111
 B  000
 C  001
 D  010
 E  011
 H  100
 L  101
Mem 110

    RP 
BC  00 
DE  01 
HL  10 

    CCC    
nz  000 Z=0 Результат не равен нулю
z   001 Z=1 Результат равен нулю
nc  010 C=0 Перенос не установлен
c   011 C=1 Перенос установлен
np  100 P=0 Число единиц результата нечетно
p   101 P=1 Число единиц результата четно
ns  110 S=0 Результат неотрицателен (ноль в старшем разряде)
s   111 S=1 Результат отрицателен (единица в старшем разряде)

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

6502

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

  Cпособ формирования адреса BBB  
ZP Addr8 001 Восьмиразрядный адрес байта в нулевой странице является частью команды
ZPX Addr8+X 101 Восьмиразрядный адрес, являющийся частью команды, складывается со значением в регистре X
ZPY Addr8+Y 101 Восьмиразрядный адрес, являющийся частью команды, складывается со значением в регистре Y (только в командах ldx и stx)
ABS Addr16 011 Шестнадцатиразрядный адрес является частью команды
ABX Addr16+Y 111 Шестнадцатиразрядный адрес, являющийся частью команды, складывается со значением в регистре X
ABY Addr16+Y 110 Шестнадцатиразрядный адрес, являющийся частью команды, складывается со значением в регистре Y
ABY Addr16+Y 111 Шестнадцатиразрядный адрес, являющийся частью команды, складывается со значением в регистре Y (только в командах ldx и stx)
NDX [Addr8+X]16 000 Шестнадцатиразрядный адрес извлекается из двух байт в нулевой странице, на которые указывает сумма являющегося частью команды восьмиразрядного адреса и зачения в регистре X
NDY [Addr8]16+Y 100 Шестнадцатиразрядный адрес извлекается из двух байт в нулевой странице, на которые указывает являющийся частью команды восьмиразрядный адрес, после чего к нему прибавляется значение в регистре Y

   CCC    
pl 000 N=0 Результат неотрицателен (ноль в старшем разряде)
mi 001 N=1 Результат отрицателен (единица в старшем разряде)
vc 010 V=0 Переполнение не зафиксировано
vs   011 V=1 Зафиксировано переполнение
сс 100 С=0 Перенос сброшен
cs 101 C=1 Перенос установлен
ne 110 Z=0 Результат не равен нулю
eq 111 Z=1 Результат равен нулю

8086

Команда может иметь длину от одного до шести байт. Первый байт команды всегда содержит код операции и может включать однобитовые поля направления передачи (D), величина сдвига (V), разрядности (W) трехбитовое поле, определяющее регистр (REG) или черырехбитовое условие перехода (COND), соответствующее значению одного, двух или трех битов регистра состояния PSW (CF - перенос, PF - четность, ZF - ноль, SF - знак, OF - переполнение) - их значения устанавливаются при выполнении арифметических и логических операций. Коды некоторых команд не умещаются в один байт, оставшиеся биты находятся во втором байте команды.

Второй байт обычно содержит поля, указывающие разрядность смещения/использование второго регистра (MOD, MM), регистр (REG) и способ формирования адреса, т.е. используемые индексные регистры (R/M) (байт MOD-REG-R/M) или сегментный регистр (SR). Следующие байты, если они есть, содержат смещения и данные.

Направление D
Из регистра 0
В регистр 1

Величина сдвига V
1 0
В регистре CL 1

Разрядность W
Байт 0
Слово 1

Разрядность смещения MM
Отсутствует 00 
Байт 01 
Слово 10 
Второй операнд-регистр, R/M=REG 11 

      REG
DST
SRC
AX/AL 000
BX/BL 011
CX/CL 001
DX/DL 010
SP/AH 100
DI/BH 111
BP/CH 101
SI/DH 110

    SR 
CS  01 
SS  10 
DS  11 
ES  00 

Cпособ формирования адреса R/M
DS:[BX+Ofs] 111
DS:[SI+Ofs] 100
DS:[DI+Ofs] 101
DS:[Ofs16](MM=00)/SS:[BP+Ofs](MOD!=00) 110
DS:[BX+SI+Ofs] 000
DS:[BX+DI+Ofs] 001
SS:[BP+SI+Ofs] 010
SS:[BP+DI+Ofs] 011

    COND    
o 0000 OF=1 Произошло переполнение
no 0001 OF=0 Переполнение не произошло
b/nae 0010 CF=1 Перенос установлен (a ниже b), слова ниже и выше предполагают сравнение чисел без знака
nb/ae 0011 CF=0 Перенос не установлен (a не ниже b)
z/e 0100 ZF=1 Результат равен нулю
nz/ne 0101 ZF=0 Результат не равен нулю
be/na 0110 CF=1 | ZF=1 a ниже или равно b
a 0111 CF=0 & ZF=0 a выше b
s 1000 SF=1 Результат отрицателен
ns 1001 SF=0 Результат неотрицателен
p 1010 PF=1 Младший байт результата содержит четное число единиц
np 1011 PF=0 Младший байт результата содержит нечетное число единиц
l 1100 SF!=OF a меньше b, слова меньше и больше предполагают сравнение чисел со знаком
nl/ge 1101 SF=OF a больше или равно b
le 1110 SF!=OF | ZF=1 a меньше или равно b
g 1111 SF=OF & ZF=0 a больше b

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

i386

Команда может иметь длину от одного до одиннадцати байт. Первый байт команды всегда содержит код операции и может включать однобитовые поля направления передачи (D), величина сдвига (V), разрядности (W) трехбитовое поле, определяющее регистр (REG) или черырехбитовое условие перехода (COND). Коды некоторых команд не умещаются в один байт, оставшиеся биты находятся во втором байте команды.

За кодом операции может следовать байт MOD-REG-R/M, за ним может следовать байт масштаба, индекса и базы адреса (SCALE-INDEX-BASE, SIB). Следующие байты, если они есть, содержат смещения и данные. Коды REG такие же как и в процессоре 8086 (но по умолчанию они соответствуют восьми- и тридцатидвухразрядным регистрам), коды R/M изменены, они определяют индексный регистр (в роли которого может выступать любой регистр данных) или наличие байта SIB.

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

Cпособ формирования адреса R/M
DS:[EAX+Ofs] 000
DS:[EBX+Ofs] 011
DS:[ECX+Ofs] 001
DS:[EDX+Ofs] 010
DS:[ESI+Ofs] 110
DS:[EDI+Ofs] 111
DS:[Ofs32](MOD=00)/SS:[EBP+Ofs](MOD!=00) 101
Используется байт SIB 100

При использовании байта SIB адрес формируется по формуле

  SEG:[BBB + SS * IND + Ofs]

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

Наличие и разрядность Ofs определяется полем MM(MOD) или полем BBB(BASE), два из трех слагаемых могут отсутствовать, селектор SEG определяется базовым регистром - SS, при использоваии EBP/ESP и DS в остальных случаях, значения полей SS(SCALE), IND(INDEX) и BBB(BASE) приведены ниже:

Множитель SS
x1 00
x2 01
x4 10
x8 11

Индекс IND
EAX 000
EBX 011
ECX 001
EDX 010
ESI 110
EDI 111
EBP 101
Нет 100

База BBB
EAX 000
EBX 011
ECX 001
EDX 010
ESI 110
EDI 111
Ofs32(MM=00)/EBP(MM!=00) 101
ESP 100

Athlon64

Команды имеют значительное сходство с командами i386, но для работы с шестидесятичетырехразрядными операндами (равно как и с добавленными регистрами R8-R15) команде должен предшествовать префикс REX, четыре младших бита которого используются для указания разрядности операндов (W), расширения слева поля REG байта MOD-REG-R/M (R), поля IND байта SIB (X), поля R/M байта MOD-REG-R/M или поля BBB байта SIB или поля REG кода операции (B). Единица в бите W указывает на использование шестидесятичетырехразрядных операндов. Префикс имеет следующую структуру:

0100 W R X B

Значения префикса от 0x40 до 0x47 совпадают с однобайтными командами inc и dec процессоров 8086 и i386, так что возможно использование только длинной (с байтом MOD-REG-R/M) формы этих команд.

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

Шестидесятичетырехразрядный адрес может использоваться лишь в нескольких командах (?).

8051

Команды имеют длину от одного до трех байт. При выполнениии арифметических, логических команд и некорорых других команд устанавливаются значения битов регистра состояния PSW (C - перенос, AC - дополнительный перенос, OV - переполнение P - четность, бит нулевого результата отсутствует). PSW также содержит два бита выбора банка регистров (RS1:RS0).

Число команд довольно велико.

PIC10/12/16

Команды имеют фиксированную длину - одно двенадцати- (PIC10) или четырнадцатиразрядное (PIC12/PIC16) слово, состоящее из нескольких полей. Код операции в трех-шести(?) старших битах присутствует всегда, в оставшихся битах в зависимости от команды находятся номер регистра, флаг направления, значение константы или младшие биты адреса перехода. При выполнениии арифметических, логических команд и некорорых других команд устанавливаются значения битов регистра состояния STATUS (C - перенос, DC - дополнительный перенос, Z - ноль). В большинстве моделей длины команды недостаточно для указания регистра, выполнение команды зависит от значения битов выбора банка регистра состояния или регистра выбора банка (это зависит от типа контроллера) . Длины команды также недостаточно для хранения полного адреса, поэтому старшие биты загружаются из регистра PCLATCH, в который они должны быть записаны перед выполнением перехода.

Связь длины команды с обозначением микросхемы по-видимому отсутствует, так что сказанное выше не совсем верно. В частности, микроконтроллеры PIC16F59 в сорокавыводном корпусе PDIP и сорокачетырехвыводном TQFP являются представителями PIC10.

AVR

Команды состоят из одного или двух шестнадцатиразрядных слов, второе слово содержит адрес данных, адрес перехода или его часть. При выполнениии арифметических, логических команд и некорорых других команд устанавливаются значения битов регистра состояния SREG (C - перенос, Z - ноль, N - отрицательное значение, V - переполнение, S - знак, H - дополнительный перенос). Значение флага S устанавливается равным единице при несовпадении значений флагов N и V, и нулю при совпадении. Наличие этого дополнительного флага делает достаточной зависимость команд условных переходов только от одного флага регистра состояния.

[8001]

Вымышленный восьмиразрядный микроконтроллер, реализованный на отладочной плате FPGA Cyclone IV. Все команды имеют длину 1 байт - предпоагалось, что это упростит реализацию. Память программ и память данных могут иметь объем до 64 килобайт каждая, первые 256 байт памяти данных могут использоваться как адресуемый регистром S стек. 8 портов ввода/вывода находятся в своем адресном пространстве.

Арифметические операции выполняются над парами регистров B/D и C/E, в разных вариантах реализации результат операции помещается в регистр A и/или в первый регистр пары (из-за не слишком обоснованного желания не выполнять в одном такте чтение из регистра и запись в него же). Используемая пара регистров определяется одним битом команды. Из-за того-же желания не изменять читаемый регистр был вариант, в котором команды инкремена и декремента записывали измененное значение регистра в регистр А и изменить значение в самом регистре можно было с помощью последующей команы пересылки (mov). Это все можно обойти введением дополнительного скрытого от программиста регистра, да и проблема изменения читаемого регистра существует только если он построен на защелках (latch). Двухступенчатые триггеры свободны от этого недостатка.

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

Из 256 кодов команд не используются 12 из группы команд переходов - добавление каких-то новых команд может потребовать отказа от реализованых. Восемь бит на код команд это очень мало и не зря во многих микроконтроллерах используются более длинные коды.

Регистры имеют следующие трехразрядные коды:

Регистр Код Примечание
B 000  
C 001  
D 010  
E 011  
H 100  
L 101  
A/F 110 Интерпретация кода зависит от команды
S 111  

Пары регистров имеют следующие одноразрядные коды:

Пара Код
B/D 0
C/E 1

ARM

Команды ARM состоят из одного тридцатидвухразрядного слова и содержат ряд полей, в том числе четырехразрядное поле условия. За счет этого любая команда может быть пропущена без использования условного перехода. Также есть поле запрета/разрешения модификации регистра флагов APRS. Команды обработки данных двух- и трехадресные, т.е. два операнда могут быть взяты из двух регистров, а результат помещен в третий.

Большинство команд Thumb не содержат поля условия, вместо него в набор команд Thumb-2 был введен так называемый IT-блок (If-Then-(Else)-блок) - шестнадцатиразрядная команда, определяющая условия выполнения одной-четырех последующих команд. Что касается модификации регистра флагов APRS, то одни инструкции модифицируют его, другие нет и это может быть источником ошибок при написании программ на ассемблере.

Коды условий переходов следующие:

    COND    
eq 0000 Z=1 Результат равен нулю
ne 0001 Z=0 Результат не равен нулю
cs/hs 0010 С=1 Перенос установлен (higher or same - a выше или равно b, слова ниже и выше предполагают сравнение чисел без знака)
cс/lo 0011 С=0 Перенос не установлен
mi 0100 N=1 Знак установлен
pl 0101 N=1 Знак не установлен
vs 0110 V=1 Переполнение установлено
0111 V=0 Переполнение не установлено
hi 1000 C=1 & Z=0 a выше b
ls 1001 C=0 | Z=1 a ниже или равно b
ge 1010 N=V a больше или равно b
lt 1011 N!=V a меньше b
gt 1100 N=V & Z=0 a больше b
le 1101 N!=V | Z=1 a меньше или равно b

MIPS

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

Команды передачи данных

IBM System/360

PDP-11

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

4004

8080

Универсальные команды

Неуниверсальные команды, работающие только с аккумулятором или парой регистров HL

6502

Вторая тройка бит определяет способ адресации. Если получателем или источником данных является индексный регистр X или Y, он сам не может использоваться в качестве индекса и косвенные способы формирования адреса (NDX и NDY) недоступны. Помещаться в стек могут только значения из аккумулятора и регистра состояния, извлекаемые из стека значения могут помещаться только в эти два регистра. Два младших бита кода команды определяют регистр (?). В ассемблерной записи получатель и источник данных указывается в мнемонике, а не в операнде, поэтому команд довольно много.

8086

За исключением загрузки константы, операций с портами ввода/вывода и со стеком, второй байт команды - байт MOD-REG-R/M. Приведены только варианты команд, аналогичные командам 8080, прочие варианты получаются заменой значений полей MOD и R/M. Команды чтения из памяти и записи в память отличаются только битом направления D (1-й бит в коде операции).

i386

Отличия от 8086 в разрядности операндов и в других значениях поля R/M (второй байт всех перечисленных комано, кроме загрузки константы и операций со стеком).

Athlon64

Командам, имеющим дело с шестидесятичетырехразрядными регистрами предшествует префикс REX:

8051

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

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

Если в системе используется дополнительная микросхема памяти, получателем или источником данных всегда является регистр-аккумулятор A, адресация памяти только косвенная (с использованием регистра-указателя DPTR, или одного из регистров R0, R1) - эти четыре команды не приведены.

PIC10

PIC12/16

AVR

[8001]

ARM/Thumb

MIPS

Команды обработки данных

IBM System/360

PDP-11

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

4004

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

8080

Команды обработки байтов

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

Дополнительные команды, работающие с парами регистров

6502

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

8086

В эту группу входят арифметические операции, битовые операции И, ИЛИ, исключающее ИЛИ и сдвиги. Во всех командах расположение первого операнда и результата совпадают. За исключением команд умножения и деления это может быть как регистр, так и ячейка памяти. Первый операнд команды умножения всегда AX или AL, деления - DX:AX или AH:AL, результат - DX:AX или AH:AL. При делении в DX или AH помещается остаток.

i386

Athlon64

Команды обработки шестидесятичетырехразрядных данных такие же, как и тридцатидвухразрядных, но им предшествует префикс REX:

8051

PIC10

PIC12/16

AVR

[8001]

Во всех командых DST и SRC могут быть только B/D или C/E.

ARM/Thumb

MIPS

Команды передачи управления

IBM System/360

PDP-11

Условные переходы только относительные, безусловные переходы и переходы к подпрограмме могут быть абсолютными и относительными. Здесь приведены только команды относительных переходов, соответствующие аналогичным командам процессоров 80x86, но есть и более экзотические варианты.

4004

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

Комбинированная команда (она одна?)

8080

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

6502

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

8086

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

Все перечисленные ниже команды кроме int выполняют переходы в пределах одного сегмента, т.е. не изменяют значение CS. Команды переходов/вызовов/возвратов в другой сегмент кода также существуют, но в них значение CS задается абсолютно и, соответственно, перемещение программы из одной области памяти в другую невозможно. В системе MS-DOS EXE-файл содержит таблицу перемещений, содержащую адреса, сегментные части которых должны скорректированы перед запуском программы.

i386

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

Athlon64

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

8051

Комбинированные команды

PIC10

Комбинированные команды

PIC12/16

Комбинированные команды

AVR

[8001]

ARM/Thumb

MIPS

Hello, World!

В соответствии с традицией, первая программа должна вывести на экран приветствие вроде Hello, World! Эта программа очень проста и может быть написана непосредственно в машинном коде. Код зависит от процессора, операционной системы и используемого устройства вывода. В некотором смысле такая программа для микроконтроллера скрывает меньше.

Чтобы выполнить программу необходима соответствующая машина или ее программный эмулятор. Если речь о реальных микроконтроллерах, потребуется некоторое оборудование:

Можно купить готовую плату с установленными на ней программатором, микроконтроллером и какими-либо периферийными устройствами (как минимум, светодиодом) например, Arduino или STM Nucleo. Также можно купить готовый комплект, содержащий все перечисленное и, возможно, что-то еще.

Если покупать отдельно, можно рекомендовать

Хотя программатор USBASP и дешев, сэкономить не получится, цена программатора и микроконтроллера лишь немного меньше цены китайского клона платы Arduino UNO. К тому же эта плата способна без какого-либо дополнительного оборудования передавать данные на персональный компьютер и принимать их от него. Она также может использоваться как программатор других микроконтроллеров (не только AVR).

Запись программы в контроллер платы Arduino обычно происходит не так, как в отдельно стоящий микроконтроллер и в этом есть некоторая "магия". Часть памяти программ занимает так называемый загрузчик (bootloader) и работа контроллера начинается с исполнения его кода. Если загрузчик обнаруживает попытку записи программы, он предпринимает соответствующие действия, если нет - передает управление основному коду.

Указанная макетная плата представляется более хорошим вариантом, чем другая распространенная плата MB-102, но также не лишена недостатков - шины питания имеющегося у автора экземпляра не обеспечивают надежного контакта с тонкими выводами. Обе платы существенно хуже Wishboard WBU-504, но и намного дешевле.

Из трех сотен резисторов большая часть не понадобится, но при покупке на ebay или aliexpress это, по-видимому, самый дешевый вариант. Резисторы лучше брать углеродистые (бежевые), обозначения на них читаются лучше чем на металлопленочных (синих). Углеродистые резисторы почему-то дороже.

Нельзя покупать светодиодную матрицу 8x8 3 мм - по какой-то причине рассояние между рядами ее выводов (24 мм) не соответствует шагу отверстий на плате (2.54 мм). Матрица 8x8 3.7 мм может быть установлена, но для ее подключения потебуются короткие жесткие перемычки или две макетные платы.

Кнопки 6x6x5 мм по-видимому самые удобные. Кнопки 6x6x4.3 мм чувствуются пальцем хуже.

EDSAC

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

Важно! Перед нажатием кнопки Start должен быть выбран загрузчик Initial Order 1.

Сразу после загрузки программы она останавливается, ее выполнение может быть продолжено нажатием кнопки Reset или многократного нажатия кнопки Single E.P. во втором случае выполняется одна комана и машина останавливается. На экранах можно видеть содержимое регистров и памяти (нужно выбрать Long Tank 1, содержащий ячейки памяти с 32 до 63).

Если заменить первую команду ZS на XS, останвка произойдет после однократного выполнения программы.

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

Первый вариант:

        T53S  [EOF position]
  [32]  ZS    [hlt]
  [33]  O45S  [prn]
  [34]  O46S  [prn]
  [35]  O47S  [prn]
  [36]  O48S  [prn]
  [37]  O49S  [prn]
  [38]  O50S  [prn]
  [39]  O51S  [prn]
  [40]  O52S  [prn]
  [41]  ZS    [hlt]
  [42]  T44S  [clr Acc]
  [43]  E33S
  [44]  0S    [Tmp]
  [45]  *F    [Letter shift]
  [46]  HS
  [47]  ES
  [48]  LS
  [49]  LS
  [50]  OS
  [51]  @S    [CR]
  [52]  &S    [LF]

Второй вариант:

        T68S  [EOF position]
  [32]  ZS    [hlt]
  [33]  T59S  [clr Acc]
  [34]  A56S  [lda Ind0]
  [35]  T57S  [sta Ind]
  [36]  A55S  [lda Cmd]
  [37]  A57S  [add Ind]
  [38]  T39S  [sta Cmd]
  [39]  AS    [lda Ch]
  [40]  T58S  [sta Tmp]
  [41]  H58S  [ldm Tmp]
  [42]  C54S  [and One]
  [43]  S54S  [sub One]
  [44]  E52S  [jns 52]
  [45]  O58S  [prn Tmp]
  [46]  T58S  [clr Acc]
  [47]  A57S  [add Ind]
  [48]  A54S  [add One]
  [49]  A54S  [add One]
  [50]  T57S  [sta Ind]
  [51]  E36S  [jns 36]
  [52]  ZS    [hlt]
  [53]  E33S  [jns 33]
  [54]  0D    [One]
  [55]  AS    [Add Cmd]
  [56]  060S  [Ind0]
  [57]  0S    [Ind]
  [58]  0S    [Tmp]
  [59]  *S    [Letter shift]
  [60]  HS
  [61]  ES
  [62]  LS
  [63]  LS
  [64]  OS
  [65]  @S    [CR]
  [66]  &S    [LF]
  [67]  0D    [EOS]

PDP-11

Предполагается использование эмулятора simhv/pdp11 без операционной системы, вывод на телетайп. В реальную машину программа может быть введена с помощью пульта (blinkenlight console?), в память эмулятора - с помощью команд

   deposit addr, value

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

   go addr

В следующих примерах addr=10008 (020016)

  Адрес  Код        Адрес(8)  Код(8)         Метка    Мнемоника
  -----  ---------  --------  -------------  -------  ---------
  0200   15C2 FF74  001000    012702 177564           mov  #177564, R2    ;Регистр статуса телетайпа
  0204   15C0 0048  001004    012700 000110           mov  #'H',    R0
  0208   9032 0002  001010    110062 000002  @Wait1:  movb (R0),    2(R2) ;Запись в регистр данных телетайпа
  020C   8BCA       001014    105712                  tstb (R2)           ;Проверка завершения записи
  020E   80FE       001016    100376                  bpl  @Wait1         ;Если в разряде 7 регистра статуса телетайпа 0 - повторить проверку
  0210   15C0 0065  001020    012700 000145           mov  #'e',    R0
  0214   9032 0002  001024    110062 000002  @Wait2:  movb (R0),    2(R2)
  0218   8BCA       001030    105712                  tstb (R2)
  021A   80FE       001032    100376                  bpl  @Wait2
  ...
  0252   0000       001122    000000                  halt

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

Символы можно выводить в цикле:

  Адрес  Код        Адрес(8)  Код(8)         Метка    Мнемоника
  -----  ---------  --------  -------------  -------  ---------
  0200   15C2 FF74  001000    012702 177564           mov  #177564, R2    ;Регистр статуса телетайпа
  0204   11C1       001004    010701                  mov  R7,      R1
  0206   11C1 0014  001006    062701 000024           add  R1,      #24   ;R1 = @Text
  020A   9440       001012    112100         @Loop:   movb (R1)+,   R0
  020C   0305       001014    001405                  beq  @Exit
  020E   9032 0002  001016    110062 000002  @Wait:   movb (R0),    2(R2) ;Запись в регистр данных телетайпа
  0212   8BCA       001022    105712                  tstb (R2)           ;Проверка завершения записи
  0214   80FE       001024    100376                  bpl  @Wait          ;Если в разряде 7 регистра статуса телетайпа 0 - повторить проверку
  0216   01F9       001026    000771                  br   @Loop
  0218   0000       001030    000000         @Exit:   halt
  021A   6548       001032    062510         @Text:   dw  'H' 'e'
  021C   6C6C       001034    066154                  dw  'l' 'l'
  021E   2C6F       001036    026157                  dw  'o' ','
  0220   5720       001040    053440                  dw  ' ' 'W'
  0222   726F       001042    071157                  dw  'o' 'r'
  0224   646C       001044    062154                  dw  'l' 'd'
  0226   0021       001046    000041                  dw  '!' 0

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

Возможно, после вывода символа следует проверять отсутствие ошибок в работе телетайпа (бит 15 регистра статуса телетайпа).

8080

Предполагается использование операционной системы CP/M-80 (все программы проверены в эмуляторе MYZ80 1.24). CP/M загружает программу в область памяти с начальным адресом 0x100 и выполняет переход по адресу 0x100. Программа использует две функции CP/M - вывод символа (2) и завершение программы (0):

  Адрес  Код       Метка   Мнемоника
  -----  --------  ------  ---------
  0100   0E 02             mvi  C,  2     ;Вывод символа
  0102   1E 48             mvi  E, 'H'
  0104   CD 05 00          call 5
  0107   0E 02             mvi  C,  2     ;Вывод символа
  0109   1E 65             mvi  E, 'e'
  010B   CD 05 00          call 5
  ....
  015B   0E 00             mvi  C,  0     ;Завершение программы
  015D   CD 05 00          call 5

Код имеет тот же недостаток, что и его прототип для PDP-11. Можно использовать функцию вывода строки, оканчивающейся символом $ (9):

  Адрес  Код       Метка   Мнемоника
  -----  --------  ------  ---------
  0100   0E 09             mvi  C,  9     ;Вывод строки
  0102   11 0D 01          lxi  D,  @Text
  0105   CD 05 00          call 5
  0108   0E 00             mvi  C,  0     ;Завершение программы
  010A   CD 05 00          call 5
  010D   48        @Text:  db  'H'
  010E   65                db  'e'
  010F   6C                db  'l'
  0110   6C                db  'l'
  0111   6F                db  'o'
  0112   2C                db  ','
  0113   20                db  ' '
  0114   57                db  'W'
  0115   6F                db  'o'
  0116   72                db  'r'
  0117   6C                db  'l'
  0118   64                db  'd'
  0119   21                db  '!'
  011A   24                db   $

Наконец, можно использовать функцию вывода символа в цикле:

  Адрес  Код       Метка   Мнемоника
  -----  --------  ------  ---------
  0100   21 1A 01          lxi  H,  @Text
  0103   5E        @Loop:  mov  E,  M
  0104   3E 00             mvi  A,  0
  0106   93                sub  E
  0107   CA 15 01          jz   @Exit
  010A   E5                push H
  010B   0E 02             mvi  C,  2     ;Вывод символа
  010D   CD 05 00          call 5
  0110   E1                pop  H
  0111   23                inx  H
  0112   C3 03 01          jmp  @Loop
  0115   0E 00     @Exit:  mvi  C,  0     ;Завершение программы
  0117   CD 05 00          call 5
  011A   48        @Text:  db  'H'
  011B   65                db  'e'
  011C   6C                db  'l'
  011D   6C                db  'l'
  011E   6F                db  'o'
  011F   2C                db  ','
  0120   20                db  ' '
  0121   57                db  'W'
  0122   6F                db  'o'
  0123   72                db  'r'
  0124   6C                db  'l'
  0125   64                db  'd'
  0126   21                db  '!'
  0127   00                db   0

6502

Предполагается использование операционной системы Apple DOS (все программы проверены в эмуляторе AppleWin, образ диска был сформирован с помощью CiderPress). Программа должна загружаться в область памяти с начальным адресом 0x0C00 (3072), который является атрибутом файла(?). Для загрузки и запуска нужно ввести две команды:

BLOAD HELLOWORLD
CALL 3072

Программа использует одну функцию Apple DOS - вывод символа (ее адрес 0xFDF0):

  Адрес  Код       Метка   Мнемоника
  -----  --------  ------  ---------
  0C00   A9 C8             lda  'H'|0x80
  0C02   20 F0 FD          jsr  0xFDF0    ;Вывод символа
  0C05   A9 E5             lda  'e'|0x80
  0C07   20 F0 FD          jsr  0xFDF0    ;Вывод символа
  ....
  0C41   60                rts

В старшем бите выводимого символа зачем-то должна быть единица (?). Программу можно ввести с клавиатуры используя записанный в ПЗУ интерпретатор васика, но все адреса и коды придется перевести в десятичную систему(?):

  POKE 3072, 169
  POKE 3073, 200
  ...

Код имеет тот же недостаток, что и его прототип для PDP-11. Вывод строки в цикле:

  Адрес  Код       Метка   Мнемоника
  -----  --------  ------  ---------
  0C00   A9 1E             lda  #Lo(Text)
  0C02   85 FE             sta  0xFE
  0C04   A9 C0             lda  #Hi(Text)
  0C06   85 FF             sta  0xFF
  0C08   A0 00             ldy  0x00
  0C0A   B1 FE     @Loop:  lda  (0xFE),y
  0C0C   F0 0F             beq  @Exit
  0C0E   18                clc
  0C0F   69 80             adc  #0x80
  0C11   20 F0 FD          jsr  0xFDF0    ;Вывод символа
  0C14   E6 FE             inc  0xFE
  0C16   D0 F2             bne  @Loop
  0C18   E6 FF             inc  0xFF
  0C1A   4C 0A 0C          jmp  @Loop
  0C1D   60        @Exit:  rts
  0C1E   48        @Text:  db  'H'
  0C1F   65                db  'e'
  0C20   6C                db  'l'
  0C21   6C                db  'l'
  0C22   6F                db  'o'
  0C23   2C                db  ','
  0C24   20                db  ' '
  0C25   57                db  'W'
  0C26   6F                db  'o'
  0C27   72                db  'r'
  0C28   6C                db  'l'
  0C29   64                db  'd'
  0C2A   21                db  '!'
  0C2B   00                db   0

Если ограничить длину строки 254 символами, можно увеличивать не адрес в ячейках 0xFE и 0xFF, а смещение в регистре Y. Вместо сложения можно и правильно использовать логическое ИЛИ.

8086

Предполагается использование операционной системы MS-DOS (все программы проверены в эмуляторе DOSBox 0.72). При запуске программы формата COM DOS выделяет свободную область памяти, выровненную по границе сегмента (т.е. имеющую адрес с нулевыми младшими четырьмя разрядами), в ее начало записывает так называемый префикс программного сегмента (PSP) длиной 256 байт (0x100), загружает код программы начиная с адреса Seg(PSP):0x100, заполняет сегментные регистры DS и SS значением Seg(PSP) и выполняет дальний переход по адресу PSP:0x100.

Программа использует две функции DOS - вывод символа (2) и завершение программы (4C):

  Адрес  Код       Метка   Мнемоника
  -----  --------  ------  ---------
  0100   B4 02             mov  AH,  2    ;Вывод символа
  0102   B2 48             mov  DL, 'H'
  0104   CD 21             int  21H
  0106   B4 02             mov  AH,  2    ;Вывод символа
  0108   B2 65             mov  DL, 'e'
  010A   CD 21             int  21H
  ....
  014E   B4 4C             mov  AH,  4CH  ;Завершение программы
  0150   B0 00             mov  AL,  0
  0152   CD 21             int  21H

Можно использовать функцию вывода строки, оканчивающейся символом $ (9):

  Адрес  Код       Метка   Мнемоника
  -----  --------  ------  ---------
  0100   B4 09             mov  AH,  9    ;Вывод строки
  0102   BA 0D 01          mov  DX,  @Text
  0105   CD 21             int  21H
  0107   B4 4C             mov  AH,  4CH  ;Завершение программы
  0109   B0 00             mov  AL,  0
  010B   CD 21             int  21H
  010D   48        @Text:  db  'H'
  010E   65                db  'e'
  010F   6C                db  'l'
  0110   6C                db  'l'
  0111   6F                db  'o'
  0112   2C                db  ','
  0113   20                db  ' '
  0114   57                db  'W'
  0115   6F                db  'o'
  0116   72                db  'r'
  0117   6C                db  'l'
  0118   64                db  'd'
  0119   21                db  '!'
  011A   24                db   $

Наконец, можно использованить функцию вывода символа в цикле:

  Адрес  Код       Метка   Мнемоника
  -----  --------  ------  ---------
  0100   BB 18 01          mov  BX,  @Text
  0103   8A 17     @Loop:  mov  DL,  DS:[BX]
  0105   B0 00             mov  AL,  0
  0107   2A C2             sub  AL,  DL
  0109   74 07             jz   @Exit
  010B   B4 02             mov  AH,  2    ;Вывод символа
  010D   CD 21             int  21H
  010F   43                inc  BX
  0110   FB F1             jmp  @Loop
  0112   B4 C4     @Exit:  mov  AH,  4EH  ;Завершение программы
  0114   B0 00             mov  AL,  0
  0116   CD 21             int  21H
  0118   48        @Text:  db  'H'
  0119   65                db  'e'
  011A   6C                db  'l'
  011B   6C                db  'l'
  011C   6F                db  'o'
  011D   2C                db  ','
  012E   20                db  ' '
  012F   57                db  'W'
  0130   6F                db  'o'
  0131   72                db  'r'
  0132   6C                db  'l'
  0133   64                db  'd'
  0134   21                db  '!'
  0135   00                db   0

i386

Предполагается использование операционной системы Linux/386. Использование Linux/AMD64 возможно. Программа формата ELF32 состоит из заголовка и сегмента кода, начальный логический адрес которого указываются в заголоке. Программа использует две функции - запись в файл (4) и завершение программы (1). Перед выводом строки выполняется подсчет числа символов, его можно вычислить заранее, но это не сделано чтобы продемонстрировать использование большего числа различных команд. Заголовок программы пропущен, его формирование несложно, но длина превышает длину кода:

  Адрес     Код             Метка   Мнемоника
  --------  --------------  ------  ---------
  08048000  7F                      db   7FH        ;Заголовок ELF32
  08048001  45                      db  'E'
  08048002  4C                      db  'L'
  08048003  46                      db  'F'
  ........
  08048054  B9 80 80 04 08          mov  ECX,  @Text
  08048059  89 CA                   mov  EDX,  ECX
  0804805B  8A 02           @Loop:  mov  AL,  [EDX]
  0804805D  B4 00                   mov  AH,   0
  0804805F  2A E0                   sub  AH,   AL
  08048061  74 03                   jz   @Exit
  08048063  42                      inc  EDX
  08048064  EB F5                   jmp  @Loop
  08048066  B8 04 00 00 00  @Exit:  mov  EAX,  4    ;Запись в файл
  0804806B  BB 01 00 00 00          mov  EBX,  1
  08048070  2B D1                   sub  EDX,  ECX
  08048072  CD 80                   int  80H
  08048074  B8 01 00 00 00          mov  EAX,  1    ;Завершение программы
  08048079  BB 00 00 00 00          mov  EBX,  0
  0804807E  CD 80                   int  80H
  08048080  48              @Text:  db  'H'
  08048081  65                      db  'e'
  08048082  6C                      db  'l'
  08048083  6C                      db  'l'
  08048084  6F                      db  'o'
  08048085  2C                      db  ','
  08048086  20                      db  ' '
  08048087  57                      db  'W'
  08048088  6F                      db  'o'
  08048089  72                      db  'r'
  0804808A  6C                      db  'l'
  0804808B  64                      db  'd'
  0804808C  21                      db  '!'
  0804808D  00                      db   0

Athlon64

Предполагается использование операционной системы Linux/AMD64. Программа формата ELF64 состоит из заголовка и сегмента кода, начальный адрес которого выбран равным 2^32, для обращения к нему тридцатидвухразрядного адреса недостаточно. Программа использует две функции - запись в файл (1) и завершение программы (0), в силу каких-то причин номера функций и правила передачи параметров отличаются от Linux/386. Перед выводом строки также выполняется подсчет числа символов:

  Адрес       Код                            Метка   Мнемоника
  ----------  -----------------------------  ------  ---------
  0100000000  7F                                     db   7FH        ;Заголовок ELF64
  0100000001  45                                     db  'E'
  0100000002  4C                                     db  'L'
  0100000003  46                                     db  'F'
  ..........
  0100000078  48 BE AD 00 00 00 01 00 00 00          mov  RSI,  @Text
  0100000082  48 89 F2                               mov  RDX,  RSI
  0100000085  8A 02                          @Loop:  mov  AL,  [RDX]
  0100000087  B4 00                                  mov  AH,   0
  0100000089  2A E0                                  sub  AH,   AL
  010000008B  74 05                                  jz   @Exit
  010000008D  48 FF C2                               inc  RDX
  0100000090  EB F3                                  jmp  @Loop
  0100000092  B8 01 00 00 00                 @Exit:  mov  RAX,  1    ;Запись в файл
  0100000097  BF 01 00 00 00                         mov  RDI,  1
  010000009C  48 2B D6                               sub  RDX,  RSI
  010000009F  0F 05                                  syscall
  01000000A1  B8 3C 00 00 00                         mov  RAX,  3CH  ;Завершение программы
  01000000A6  BF 00 00 00 00                         mov  RDI,  0
  01000000AB  0F 05                                  syscall
  01000000AD  48                             @Text:  db  'H'
  01000000AE  65                                     db  'e'
  01000000AF  6C                                     db  'l'
  01000000B0  6C                                     db  'l'
  01000000B1  6F                                     db  'o'
  01000000B2  2C                                     db  ','
  01000000B3  20                                     db  ' '
  01000000B4  57                                     db  'W'
  01000000B5  6F                                     db  'o'
  01000000B6  72                                     db  'r'
  01000000B7  6C                                     db  'l'
  01000000B8  64                                     db  'd'
  01000000B9  21                                     db  '!'
  01000000BA  00                                     db   0

8051

Приведенный ниже код проверялся на микроконтроллере AT89S4051 в 20-выводном корпусе, но можно использовать и другие. Выбор может быть ограничен имеющимся программатором, по-видимому предпочтительны контроллеры, допускающие последовательное внутрисистемное (внутрисхемное) программирование (In-System Programming).

Если я правильно понял описание, AT89S4051 не имеет встроенного RC-генератора и для его работы необходим либо кварцевый резонатор с парой конденсаторов 5 пФ, либо внешний генератор. Первое явно проще.

Текстовый дисплей HD44780, светодиодная матрица и графический дисплей PCD8544 Чтобы реализовать задуманное нужно какое-то устройство вывода. Можно использовать текстовый дисплей с контроллером HD44780, может быть, можно использовать и какой-то графический дисплей, например PCD8544 (Nokia 5110). В последнем случае самой сложной частью работы будет именно управление дисплеем и формирование символов из точек. Использовать семисегментный индикатор проще, но он может отобразить не все буквы, так что придется либо ограничиться первой половиной фразы, либо заменить слово WORLD чем-то другим, например обозначением микроконтроллера 89S4051. Как отобразить запятую тоже непонятно, да и выглядит это не очень привлекательно. Матрицы из тридцати пяти (5x7) или шестидесяти четырех (8x8) светодиодов позволяют отображать любые символы английского алфавита, бегущая строка на них выглядит вполне пристойно, но символы также нужно формировать из точек. Кроме того, не у всякого микроконтроллера имеется достаточно выводов для их непосредственного подключения (AT89S4051 имеет пятнадцать выводов, одну строку или колонку матрицы 8x8 подключить некуда, но с этим в принципе можно смириться).

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

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

Приведенные здесь программы лишь немного сложнее, а вот их эквивалент в виде электронной схемы намного сложнее простого генератора (но на микросхеме FPGA/CPLD реализуется легко).

Для написания программы и изготовления соответствующего hex-файла использовалась интегрированная среда MCU8051IDE.

Чтобы записать программу в контроллер необходим программатор. Автор использовал плату Arduino Uno и программатор, основанный на программаторе для AT89S52. Изменено и/или исправлено было следующее:

Последнее не совсем корректно, наверное было бы правильнее реализовать обмен сообщениями и ждать сообщения о готовности.

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

Светодиод с ограничивающим ток резистором 220 ом должен быть подключен ко второму биту порта 1 (вывод 14 AT892S4051) и плюсу источника питания - выход микроконтроллера несимметричен. Светодиод горит при низком уровне на выходе. Хотя это и не очень хорошо, можно включать сведодиод и высоким уровнем. Для этого нужно резистором соединить выход контроллера с плюсом питания, а светодиод подключить к выходу и земле. Резистор нужен чтобы увеличить ток через светодиод. Такая схема потребляет ток и при высоком и при низком уровне на выходе.

Имеет смысл подключать контакты MOSI, MISO, SCK, RST/VPP и VCC через резисторы 220 ом, это должно защитить плату Arduino от повреждения при ошибках сборки схемы.

Сброс микроконтроллера осуществляется кратковременной подачей напряжения питания на вывод RST/VPP.

Прерывания не разрешены, так что никаких ограничений на размещение кода нет.

  Адрес  Код       Метка    Мнемоника
  -----  --------  -------  ---------
  0000   02 00 16           ljmp  INIT
  0003   7E 41     PAUSE:   mov   CM0,   #0x41   ;CM0=R6
  0005   7D D7              mov   CL0,   #0xD7   ;CL0=R5
  0007   DD FE     LOOP_L:  djnz  CL0,   LOOP_L
  0009   DE FC              djnz  CM0,   LOOP_L
  000B   DF F6              djnz  CH0,   PAUSE   ;CH0=R7
  000D   22                 ret
  000E   C2 92     SIGN:    clr   LED            ;LED=P1.2
  0010   12 00 03           lcall PAUSE
  0013   D2 92              setb  LED
  0015   22                 ret
  0016   75 81 2F  INIT:    mov   SP,    #0x2F
  0019   7F 08     MAIN:    mov   CH0,   #DOT    ;DOT=0x08, H=....
  001B   12 00 0E           lcall SIGN
  001E   7F 08              mov   CH0,   #S2S    ;S2S=0x08
  0020   12 00 03           lcall PAUSE
  0023   7F 08              mov   CH0,   #DOT
  0025   12 00 0E           lcall SIGN
  0028   7F 08              mov   CH0,   #S2S
  002A   12 00 03           lcall PAUSE
  002D   7F 08              mov   CH0,   #DOT
  002F   12 00 0E           lcall SIGN
  0032   7F 08              mov   CH0,   #S2S
  0034   12 00 03           lcall PAUSE
  0037   7F 08              mov   CH0,   #DOT
  0039   12 00 0E           lcall SIGN
  003C   7F 18              mov   CH0,   #C2C    ;C2C=0x18
  003E   12 00 03           lcall PAUSE
  0041   7F 08              mov   CH0,   #DOT    ;E=.
  0043   12 00 0E           lcall SIGN
  0046   7F 18              mov   CH0,   #C2C
  0048   12 00 03           lcall PAUSE
  004B   7F 08              mov   CH0,   #DOT    ;L=.-..
  004D   12 00 0E           lcall SIGN
  0050   7F 08              mov   CH0,   #S2S
  0052   12 00 03           lcall PAUSE
  0055   7F 18              mov   CH0,   #DASH   ;DASH=0x18
  0057   12 00 0E           lcall SIGN
  005A   7F 08              mov   CH0,   #S2S
  005C   12 00 03           lcall PAUSE
  005F   7F 08              mov   CH0,   #DOT
  0061   12 00 0E           lcall SIGN
  0064   7F 08              mov   CH0,   #S2S
  0066   12 00 03           lcall PAUSE
  0069   7F 08              mov   CH0,   #DOT
  006B   12 00 0E           lcall SIGN
  006E   7F 18              mov   CH0,   #C2C
  0070   12 00 03           lcall PAUSE
  ...
  0190   7F 70              mov   CH0,   #M2M    ;M2M=0x70
  0192   12 00 03           lcall PAUSE
  0195   02 00 19           ljmp  MAIN

Функция PAUSE предназначена для задержки выполнения программы, при тактовой частоте 16 МГц задержка кратна 25 миллисекундам.

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

:10 0000 00 020016 7E41 7DD7 DDFE DEFC DFF6 22 C292 C5

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

  Адрес  Код       Метка    Мнемоника
  -----  --------  -------  ---------
  0000   75 81 2F  INIT:    mov   SP,    #0x2F    ;Вызовов функций нет, устанавливаемое после сброса значение 0x07 можно не менять
  0003   90 00 1F           mov   DPTR,  #HELLO
  0006   D2 92              setb  LED            ;LED=P1.2
  0008   7C 00     MAIN:    mov   IX,    #0x00   ;IX=R4
  000A   EC        SIGN:    mov   A,     IX
  000B   93                 movc  A,     @A+DPTR ;Чтение из памяти программы
  000C   60 FA              jz    MAIN
  000E   FF                 mov   CH0,   A       ;CH0=R7
  000F   0C                 inc   IX
  0010   B2 92              cpl   LED            ;Инверсия значения на выходе
  0012   7E 41     LOOP_H:  mov   CM0,   #0x41   ;CM0=R6
  0014   7D D7              mov   CL0,   #0xD7   ;CL0=R5
  0016   DD FE     LOOP_L:  djnz  CL0,   LOOP_L
  0018   DE FC              djnz  CM0,   LOOP_L
  001A   DF F6              djnz  CH0,   LOOP_H
  001C   02 00 0A           ljmp  SIGN
  001F   08 08     HELLO:   db    DOT,   S2S     ;DOT=0x08,  S2S=0x08, H=....
  0021   08 08              db    DOT,   S2S
  0023   08 08              db    DOT,   S2S
  0025   08 18              db    DOT,   C2C
  0027   08 18              db    DOT,   C2C     ;E=.
  0029   08 08              db    DOT,   S2S     ;L=.-..
  002B   18 08              db    DASH,  S2S     ;DASH=0x18
  002D   08 08              db    DOT,   S2S
  002F   08 18              db    DOT,   C2C
  ...
  006C   70                 db    M2M            ;M2M=0x70
  006D   00                 db    0

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

PIC10

Приведенный ниже код проверялся на микроконтроллере PIC10F200 в 8-выводном корпусе.

Для написания программы и изготовления соответствующего hex-файла использоваалась интегрированная среда MPLAB X IDE.

Чтобы записать программу в контроллер необходим программатор. Автор использовал ту же плату Arduino Uno и собранный на макетной плате упрощенный ardpicprog (ICSP-only programmer).

Приведенная схема содержит дефект - база транзистора должна быть соединена с землей резистором 5-10 кОм. Если это не сделано, при включении или перезагрузке платы Arduino база подключена к высокоомному входу, т.е. не подключена ни к чему. Кроме того, схема на одном транзисторе сразу после включения выдает высокое напряжение. Чтобы это исключить, можно добавить инвертор на еще одном одном транзисторе и в программе для Arduino изменить на противоположные константы MCLR_RESET и MCLR_VPP:

По-видимому, имеет смысл вместо аналоговых выходов использовать цифровые:

#define PIN_MCLR        8    // 0: Reset PIC, 1: MCLR is VPP voltage -> PIC10F200.PIN8
#define PIN_ACTIVITY    10   // LED that indicates read/write activity
#define PIN_VDD         2    // Controls the power to the PIC -> 220 -> PIC10F200.PIN2
#define PIN_CLOCK       4    // Clock pin -> 220 -> PIC10F200.PIN4
#define PIN_DATA        7    // Data pin  -> 220 -> PIC10F200.PIN5

#define MCLR_RESET      LOW  // PIN_MCLR state to reset the PIC
#define MCLR_VPP        HIGH // PIN_MCLR state to apply 13v to MCLR/VPP pin

Также имеет смысл подключать контакты VDD, ICSPDAT и ICSPCLK через резисторы 220 ом.

Программа для платы Arduino не поддерживает PIC10F200, но ее можно доработать. Возможно, сделанная доработка и не совсем корректна, но что есть - то есть. Почему-то при подаче напряжения на вывод MCLR/VPP до подачи напряжения на вывод VDD некорректно выполняется чтение памяти контроллера. Стирание памяти и запись при этом могут быть выполнены.

ВНИМАНИЕ! При записи программы в контроллер нужно указывать тип устройства pic10f200w (не pic10f200)!

Светодиод с ограничивающим ток резистором 220 ом должен быть подключен ко второму биту порта GPIO (вывод 3 PIC10F200) и минусу источника питания. Светодиод горит при высоком уровне на выходе. Выход микроконтроллера симметричен, так что можно подключать нагрузку и к плюсу, в этом случае потребуется изменить команды управления выводом на противоположные. Тактовый генератор встроенный (4МГц, это единственный возможный вариант), таймер сброса (watch dog timer) выключен, вывод MCLR должен быть подключен в источнику питания через резистор 10 кОм (не обязательно?).

Возможность обработки прерываний отсутствует, исполнение кода начинается с адреса 0FF, по которому должна находиться команда загрузки в рабочий регистр калибровочного коэффициента тактового генератора (movlw) или пустая команда (nop), адрес следующей исполняемой команды - 000. Значение слова конфигурации контроллера - 0FFBH, т.е. программа на ассемблере mpasm должна начинаться с директивы

  __CONFIG 0FFBH

Код программы:

  Адрес  Код   Метка    Мнемоника
  -----  ----  -------  ---------
  0000   0A11           goto   INIT
  0001   0032  PAUSE:   movwf  CH          ;CH=12H
  0002   0C82  LOOP_H:  movlw  082H
  0003   0031           movwf  CM          ;CM=11H
  0004   0CDC           movlw  0DCH
  0005   0030           movwf  CL          ;CL=10H
  0006   02F0  LOOP_L:  decfsz CL
  0007   0A06           goto   LOOP_L
  0008   02F1           decfsz CM
  0009   0A06           goto   LOOP_L
  000A   02F2           decfsz CH
  000B   0A02           goto   LOOP_H
  000C   0800           retlw  0
  000D   0546  SIGN:    bsf    GPIO,   LED ;LED=2
  000E   0901           call   PAUSE
  000F   0446           bcf    GPIO,   LED
  0010   0800           retlw  0
  0011   0CDF  INIT:    movlw  0DFH        ;Бит OPTION.T0CS(Timer0 Clock Source Select bit)=0, вход счетчика T0 отключен от вывода GP2
  0012   0002           option
  0013   0C0B           movlw  0BH         ;Вывод 2 порта GPIO используется как выход, остальные как входы
  0014   0006           tris   GPIO
  0015   0С02  MAIN:    movlw  DOT         ;DOT=2, H=....
  0016   090D           call   SIGN
  0017   0С02           movlw  S2S         ;S2S=2
  0018   0901           call   PAUSE
  0019   0C02           movlw  DOT
  001A   090D           call   SIGN
  001B   0C02           movlw  S2S
  001C   0901           call   PAUSE
  001D   0C02           movlw  DOT
  001E   090D           call   SIGN
  001F   0C02           movlw  S2S
  0020   0901           call   PAUSE
  0021   0C02           movlw  DOT
  0022   090D           call   SIGN
  0023   0C06           movlw  C2C         ;C2C=6
  0024   0901           call   PAUSE
  0025   0C02           movlw  DOT         ;E=.
  0026   090D           call   SIGN
  0027   0C06           movlw  C2C
  0028   0901           call   PAUSE
  0029   0C02           movlw  DOT         ;L=.-..
  002A   090D           call   SIGN
  002B   0C02           movlw  S2S
  002C   0901           call   PAUSE
  002D   0C06           movlw  DASH        ;DASH=6
  002E   090D           call   SIGN
  002F   0C02           movlw  S2S
  0030   0901           call   PAUSE
  0031   0C02           movlw  DOT
  0032   090D           call   SIGN
  0033   0C02           movlw  S2S
  0034   0901           call   PAUSE
  0035   0C02           movlw  DOT
  0036   090D           call   SIGN
  0037   0C06           movlw  C2C
  0038   0901           call   PAUSE
  ...
  00AD   0C1C           movlw  M2M         ;M2M=1CH
  00AE   0901           call   PAUSE
  00AF   0A15           goto   MAIN

Функция PAUSE предназначена для задержки выполнения программы, при тактовой частоте 4 МГц задержка кратна 100 миллисекундам. Реальная задержка может отличаться. Если это недопустимо, следует скорректировать частоту тактового генератора записав подходящее значение в регистр OSCCAL. Правильное значение хранится в последнем слове памяти программ нового микроконтроллера в команде movlw.

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

:10 0000 00 110A 3200 820C 3100 DC0C 3000 F002 060A CA

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

  Адрес  Код   Метка    Мнемоника
  -----  ----  -------  ---------
  0000   0CDF  INIT:    movlw  0DFH        ;Бит OPTION.T0CS(Timer0 Clock Source Select bit)=0, вход счетчика T0 отключен от вывода GP2
  0001   0002           option
  0002   0C0B           movlw  0BH         ;Вывод 2 порта GPIO используется как выход, остальные как входы
  0003   0006           tris   GPIO
  0004   0446           bcf    GPIO,   LED ;LED=2, начальная установка низкого уровня на выводе 2 порта GPIO
  0005   0070  MAIN:    clrf   IX          ;IX=10H
  0006   0919  LOOP:    call   HELLO
  0007   0033           movwf  CH          ;CH=13H
  0008   0233           movf   CH,     F   ;Установка STATUS.Z
  0009   0643           btfsc  STATUS, Z
  000A   0A05           goto   MAIN
  000B   02B0           incf   IX,     F
  000C   0C04           movlw  1 << LED
  000D   01A6           xorwf  GPIO,   F   ;Изменение состояния вывода 2 порта GPIO на противоположное
  000E   0C82  LOOP_H:  movlw  082H
  000F   0032           movwf  CM          ;CM=12H
  0010   0CDC           movlw  0DCH
  0011   0031           movwf  CL          ;CL=11H
  0012   02F1  LOOP_L:  decfsz CL
  0013   0A12           goto   LOOP_L
  0014   02F2           decfsz CM
  0015   0A12           goto   LOOP_L
  0016   02F3           decfsz CH
  0017   0A0E           goto   LOOP_H
  0018   0A06           goto   LOOP
  0019   0C1C  HELLO:   movlw  TABLE
  001A   01D0           addwf  IX,     W
  001B   0022           movwf  PCL         ;Переход
  001C   0802  TABLE:   retlw  DOT         ;DOT=2, H=....
  001D   0802           retlw  S2S         ;S2S=2
  001E   0802           retlw  DOT
  001F   0802           retlw  S2S
  0020   0802           retlw  DOT
  0021   0802           retlw  S2S
  0022   0802           retlw  DOT
  0023   0806           retlw  C2C         ;C2C=6
  0024   0802           retlw  DOT         ;E=.
  0025   0806           retlw  C2C
  0026   0802           retlw  DOT         ;L=.-..
  0027   0802           retlw  S2S
  0028   0806           retlw  DASH        ;DASH=6
  0029   0802           retlw  S2S
  002A   0802           retlw  DOT
  002B   0802           retlw  S2S
  002C   0802           retlw  DOT
  002D   0806           retlw  C2C
  ...
  0067   081C           retlw  M2M         ;M2M=1CH
  0068   0800           retlw  0           ;EOL

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

:10 0000 00 DF0C 0200 0B0C 0600 4604 7000 1909 3300 D7

PIC12/16

Приведенный ниже код проверялся на микроконтроллере PIC16F630 в 14-выводном корпусе, но можно использовать и другие, например PIC12F675 в 8-выводном корпусе. Код программы для PIC12F675 будет немного другим, нужно явно отключить аналоговый вход, сбросив второй бит порта ANSEL. Также имена портов в ассемблерном листинге должны быть другие (GPIO/TRISIO вместо PORTA/TRISA). Почему-то фирма Moicrochip использует разные имена для одного и того же порта - во всяком случае адрес и число разрядов у них совпадают.

Для написания программы и изготовления соответствующего hex-файла использоваалась упомянутая выше интегрированная среда MPLAB X IDE.

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

#define PIN_MCLR        8    // 0: Reset PIC, 1: MCLR is VPP voltage -> PIC16F630.PIN4
#define PIN_ACTIVITY    10   // LED that indicates read/write activity
#define PIN_VDD         2    // Controls the power to the PIC -> 220 -> PIC16F630.PIN1
#define PIN_CLOCK       4    // Clock pin -> 220 -> PIC16F630.PIN12
#define PIN_DATA        7    // Data pin  -> 220 -> PIC16F630.PIN13

#define MCLR_RESET      LOW  // PIN_MCLR state to reset the PIC
#define MCLR_VPP        HIGH // PIN_MCLR state to apply 13v to MCLR/VPP pin

Светодиод с ограничивающим ток резистором 220 ом должен быть подключен ко второму биту порта A (вывод 11 PIC16F630) и минусу источника питания. Светодиод горит при высоком уровне на выходе. Выход микроконтроллера симметричен, так что можно подключать нагрузку и к плюсу, в этом случае потребуется изменить команды управления выводом на противоположные. Тактовый генератор встроенный (4МГц), таймер сброса (watch dog timer) выключен, вывод MCLR должен быть подключен в источнику питания через резистор 10 кОм.

Прерывания не разрешены, так что никаких ограничений на размещение кода нет (при разрешенных прерываниях их обработчик должен начинаться с адреса 0004). Значение слова конфигурации контроллера - 31F4H, т.е. программа на ассемблере mpasm должна начинаться с директивы

  __CONFIG 31F4H

Код программы:

  Адрес  Код   Метка    Мнемоника
  -----  ----  -------  ---------
  0000   2811           goto   INIT
  0001   00A2  PAUSE:   movwf  CH          ;CH=22H
  0002   3082  LOOP_H:  movlw  082H
  0003   00A1           movwf  CM          ;CM=21H
  0004   30DC           movlw  0DCH
  0005   00A0           movwf  CL          ;CL=20H
  0006   0BA0  LOOP_L:  decfsz CL
  0007   2806           goto   LOOP_L
  0008   0BA1           decfsz CM
  0009   2806           goto   LOOP_L
  000A   0BA2           decfsz CH
  000B   2802           goto   LOOP_H
  000C   0008           return
  000D   1505  SIGN:    bsf    PORTA,  LED ;LED=2
  000E   2001           call   PAUSE
  000F   1105           bcf    PORTA,  LED
  0010   0008           return
  0011   1683  INIT:    bsf    STATUS, PR0 ;PR0=5, Выбор банка 1
  0012   1105           bcf    TRISA,  LED ;Вывод 2 порта A используется как выход
  0013   1283           bcf    STATUS, PR0 ;Выбор банка 0
  0014   3002  MAIN:    movlw  DOT         ;DOT=2, H=....
  0015   200D           call   SIGN
  0016   3002           movlw  S2S         ;S2S=2
  0017   2001           call   PAUSE
  0018   3002           movlw  DOT
  0019   200D           call   SIGN
  001A   3002           movlw  S2S
  001B   2001           call   PAUSE
  001C   3002           movlw  DOT
  001D   200D           call   SIGN
  001E   3002           movlw  S2S
  001F   2001           call   PAUSE
  0020   3002           movlw  DOT
  0021   200D           call   SIGN
  0022   3006           movlw  C2C         ;C2C=6
  0023   2001           call   PAUSE
  0024   3002           movlw  DOT         ;E=.
  0025   200D           call   SIGN
  0026   3006           movlw  C2C
  0027   2001           call   PAUSE
  0028   3002           movlw  DOT         ;L=.-..
  0029   200D           call   SIGN
  002A   3002           movlw  S2S
  002B   2001           call   PAUSE
  002C   3006           movlw  DASH        ;DASH=6
  002D   200D           call   SIGN
  002E   3002           movlw  S2S
  002F   2001           call   PAUSE
  0030   3002           movlw  DOT
  0031   200D           call   SIGN
  0032   3002           movlw  S2S
  0033   2001           call   PAUSE
  0034   3002           movlw  DOT
  0035   200D           call   SIGN
  0036   3006           movlw  C2C
  0037   2001           call   PAUSE
  ...
  00AC   301C           movlw  M2M         ;M2M=1CH
  00AD   2001           call   PAUSE
  00AE   2814           goto   MAIN

Функция PAUSE предназначена для задержки выполнения программы, при тактовой частоте 4 МГц задержка кратна 100 миллисекундам. Реальная задержка может заметно отличаться - у использованного экземпляра эта длительность менялась в пределах от 70 до 110 миллисекунд. Если это недопустимо, следует скорректировать частоту тактового генератора записав подходящее значение в регистр OSCCAL. Правильное значение хранится в последнем слове памяти программ нового микроконтроллера в команде retlw, при написании этой программы оно было благополучно стерто. Если нужна высокая точность и стабильность частоты, следует использовать кварцевый резонатор. Если его частота отличается от 4 МГц, нужно пропорционально изменить длительности сигналов (DOT, DASH, S2S, C2C, W2W) и, может быть, начальные значения в регистрах CM и CL.

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

:10 0000 00 1128 A200 8230 A100 DC30 A000 A00B 0628 3D

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

  Адрес  Код   Метка    Мнемоника
  -----  ----  -------  ---------
  0000   1683  INIT:    bsf    STATUS, PR0 ;PR0=5, Выбор банка 1
  0001   1105           bcf    TRISA,  LED ;LED=2, Вывод 2 порта A используется как выход
  0002   1283           bcf    STATUS, PR0 ;Выбор банка 0
  0003   1105           bcf    PORTA,  LED ;Начальная установка низкого уровня на выводе 2 порта A
  0004   01A0  MAIN:    clrf   IX          ;IX=20H
  0005   201A  LOOP:    call   HELLO
  0006   00A3           movwf  CH          ;CH=23H
  0007   3000           movlw  0
  0008   008A           movwf  PCLATH      ;Для PIC16F630 можно не делать, но для МК с большой памятью программ это может быть нужно
  0009   08A3           movw   CH,     F   ;Установка STATUS.Z
  000A   1903           btfsc  STATUS, Z
  000B   2804           goto   MAIN
  000C   0AA0           incf   IX,     F
  000D   3004           movlw  1 << LED
  000E   0685           xorwf  PORTA,  F   ;Изменение состояния вывода 2 порта A на противоположное
  000F   3082  LOOP_H:  movlw  082H
  0010   00A2           movwf  CM          ;CM=22H
  0011   30DC           movlw  0DC
  0012   00A1           movwf  CL          ;CL=21H
  0013   0BA1  LOOP_L:  decfsz CL
  0014   2813           goto   LOOP_L
  0015   0BA2           decfsz CM
  0016   2813           goto   LOOP_L
  0017   0BA3           decfsz CH
  0018   280F           goto   LOOP_H
  0019   2805           goto   LOOP
  001A   3000  HELLO:   movlw  high    TABLE
  001B   008A           movwf  PCLATH
  001C   3021           movlw  low     TABLE
  001D   0720           addwf  IX,     W
  001E   1803           btfsc  STATUS, C
  001F   0A8A           incf   PCLATH, F
  0020   0082           movwf  PCL         ;Переход
  0021   3402  TABLE:   retlw  DOT         ;DOT=2, H=....
  0022   3402           retlw  S2S         ;S2S=2
  0023   3402           retlw  DOT
  0024   3402           retlw  S2S
  0025   3402           retlw  DOT
  0026   3402           retlw  S2S
  0027   3402           retlw  DOT
  0028   3406           retlw  C2C         ;C2C=6
  0029   3402           retlw  DOT         ;E=.
  002A   3406           retlw  C2C
  002B   3402           retlw  DOT         ;L=.-..
  002C   3402           retlw  S2S
  002D   3406           retlw  DASH        ;DASH=6
  002E   3402           retlw  S2S
  002F   3402           retlw  DOT
  0030   3402           retlw  S2S
  0031   3402           retlw  DOT
  0032   3406           retlw  C2C
  ...
  006C   341C           retlw  M2M         ;M2M=1CH
  006D   3400           retlw  0           ;EOL

AVR

Приведенный ниже код проверялся на микроконтроллере ATmega328P в 28-выводном корпусе. К этому микроконтроллеру можно подключить различные индикаторы и дисплеи, подключить светодиод естественно тоже можно.

Для микроконтроллеров с объемом памяти программ до 8192 байт (4096 слов, например ATtiny85) этот код непригоден поскольку команды переходов и вызовов подпрограмм по 22-разрядному абсолютному адресу (jmp/call) в них не реализованы. Нужно использовать команды переходов/вызовов по 12-разрядному относительному адресу (rjmp/rcall). В принципе правильно использовать эти команды всегда, когда возможно, но для начала код jmp/call проще. Кроме этого, инициализация указателя стека должна соответствовать объему памяти данных.

Светодиод с ограничивающим ток резистором 220 ом должен быть подключен к нулевому нулевому биту порта B (PB0, вывод 14 ATmega328P) и минусу источника питания. Если вместо отдельно стоящего микроконтроллера используется плата Arduino UNO, можно использовать установленный на ней и подключенный к выводу PB5 светодиод. Для этого нужно в программе заменить константу LED с 0 на 5.

Если используется Arduino Leonardo - нужно менять и порт и вывод - светодиод подключен к выводу PC7. Соответственно, нужно использовать порты DDRC и PORTC, значение константы LED должно быт 7.

ВНИМАНИЕ! Загрузка этой программы в Arduino Leonardo нарушит нормальную работу платы, хотя ничего страшного и не произойдет. В отличие от Arduino Uno эта плата не имеет отдельного преобразователя USB-USART, ее микроконтроллер Atmega32U4 сам должен следить за USB-портом и при обнаружении попытки программирования выполнять перезагрузку. Поскольку программа этого не делает, загрузка другой программы будет возможна только если примерно за 1-2 секунды до нее нажать кнопку reset.

Светодиод горит при высоком уровне на выходе. Выход микроконтроллера симметричен, так что можно подключать нагрузку и к плюсу, в этом случае потребуется изменить команды управления выводом на противоположные. Тактовый генератор встроенный 8 МГц (байт конфигурации LFUSE=0xE2, это значение по умолчанию). Если нужна высокая точность и стабильнось частоты, следует использовать кварцевый резонатор и изменить значение LFUSE (для частот 8 - 20 МГц LFUSE=0xFF). Если частота отличается от 8 МГц, нужно изменить длительности сигналов (DOT, DASH, S2S, C2C, W2W) и, может быть, начальные значения в регистрах CM и CL.

ВНИМАНИЕ! Некорректная установка байтов конфигурации может затруднить (или даже сделать невозможным?) дальнейшее использование микроконтроллера. Например, после установки LFUSE=0xFF сделать что-либо можно только после подключения 8-20 МГц кварцевого резонатора(?).

Для изготовления hex-файла использовался ассемблер avr-as, компоновщик avr-ld и программа avr-objcopy, для прошивки микроконтроллера - та же плата Arduino и программа avrdude. Инструкция здесь. Имеет смысл подключать контакты MOSI, MISO, SCK и RESET через резисторы 220 ом.

Примитивный вариант программы почти такой же, как для контроллеров 8051 и PIC:

  Адрес  Код        Метка    Мнемоника
  -----  ---------  -------  ---------
  0000   940C 000F           jmp   INIT
  0002   E671       PAUSE:   ldi   CM,    0x61 ;CM=R23
  0003   EA68                ldi   CL,    0xA8 ;CL=R22
  0004   5061       LOOP_L:  subi  CL,    0x01
  0005   0B75                sbc   CM,    ZERO ;ZERO=R21
  0006   F7E8                brcc  LOOP_L
  0007   5081                subi  CH,    0x01 ;CH=R23
  0008   F7C8                brcc  PAUSE
  0009   9508                ret
  000A   9A28       SIGN:    sbi   PORTB, LED  ;LED=0
  000B   940E 0002           call  PAUSE
  000D   9828                cbi   PORTB, LED
  000E   9508                ret
  000F   E0D8       INIT:    ldi   R29,   0x08
  0010   EFCF                ldi   R28,   0xFF
  0011   BFDE                out   SPH,   R29  ;Инициализация указателя стека, старший байт должен записываться первым!
  0012   BFCD                out   SPL,   R28
  0013   E050                ldi   ZERO,  0x00
  0014   9A20                sbi   DDRB,  LED  ;Вывод 0 порта B используется как выход
  0015   E08F       MAIN:    ldi   CH,    DOT  ;DOT=0x0F, H=....
  0016   940E 000A           call  SIGN
  0018   E08F                ldi   CH,    S2S  ;S2S=0x0F
  0019   940E 0002           call  PAUSE
  001B   E08F                ldi   CH,    DOT
  001C   940E 000A           call  SIGN
  001E   E08F                ldi   CH,    S2S
  001F   940E 0002           call  PAUSE
  0021   E08F                ldi   CH,    DOT
  0022   940E 000A           call  SIGN
  0024   E08F                ldi   CH,    S2S
  0025   940E 0002           call  PAUSE
  0027   E08F                ldi   CH,    DOT
  0028   940E 000A           call  SIGN
  002A   E28F                ldi   CH,    C2C  ;S2S=0x2F
  002B   940E 0002           call  PAUSE
  002D   E08F                ldi   CH,    DOT  ;E=.
  002E   940E 000A           call  SIGN
  0030   E28F                ldi   CH,    C2C  ;S2S=0x2F
  0031   940E 0002           call  PAUSE
  0032   E08F                ldi   CH,    DOT  ;L=.-..
  0033   940E 000A           call  SIGN
  0035   E08F                ldi   CH,    S2S
  0036   940E 0002           call  PAUSE
  0038   E28F                ldi   CH,    DASH ;DASH=0x2F
  0039   940E 000A           call  SIGN
  003B   E08F                ldi   CH,    S2S
  0036   940E 0002           call  PAUSE
  0038   E08F                ldi   CH,    DOT
  0039   940E 000A           call  SIGN
  003B   E08F                ldi   CH,    S2S
  003C   940E 0002           call  PAUSE
  003E   E08F                ldi   CH,    DOT
  003F   940E 000A           call  SIGN
  0040   E28F                ldi   CH,    C2C
  0041   940E 0002           call  PAUSE
  ...
  00F7   ED8F                ldi   CH,    M2M  ;M2M=0xDF
  00F8   940E 0002           call  PAUSE
  00F9   940C 0015           jmp   MAIN

Цикл формирования задержки использует команды вычитания (в том числе с заемом), выход из цикла осуществляется по условию установки флага переноса (заема). Этим и объясняется начальное значение счетчика (15 вместо 16 и т.п.).

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

:10 0000 00 0C94 0F00 71E6 68EA 6150 750B E8F7 8150 BC

Можно в цикле формировать последовательность знаков и пауз, хранящуюся в массиве:

  Адрес  Код        Метка    Мнемоника
  -----  ---------  -------  ---------
  0000   E0D8       INIT:    ldi   R29,   0x08
  0001   EFCF                ldi   R28,   0xFF
  0002   BFDE                out   SPH,   R29        ;Инициализация указателя стека, старший байт должен записываться первым!
  0003   BFCD                out   SPL,   R28
  0004   E030                ldi   ZERO,  0x00       ;ZERO=R19
  0005   E041                ldi   LMASK, 1 << LED   ;LMASK=R20, LED=0
  0006   9A20                sbi   DDRB,  LED        ;Вывод 0 порта B используется как выход
  0007   9828                cbi   PORTB, LED
  0008   E0F0       MAIN:    ldi   R31,   hi8(TABLE)
  0009   E3E6                ldi   R30,   lo8(TABLE)
  000A   95C8       LOOP:    lpm                     ;Чтение байта из памяти программ
  000B   2A03                or    R0,    ZERO
  000C   F3D9                breq  MAIN
  000D   9631                adiw  R30,   1          ;inc R31:R30
  000E   B155                in    TEMP,  PORTB
  000F   2754                eor   TEMP,  LMASK
  0010   B955                out   PORTB, TEMP       ;Изменение состояния вывода 0 порта B на противоположное
  0011   2D80                mov   CH,    R0         ;CH=R24
  0012   E671       LOOP_H:  ldi   CM,    0x61       ;CM=R23
  0013   EA68                ldi   CL,    0xA8       ;CL=R22
  0014   5061       LOOP_L:  subi  CL,    0x01
  0015   0B73                sbc   CM,    ZERO
  0016   F7E8                brсс  LOOP_L
  0017   5081                subi  CH,    0x01
  0018   F7C8                brсс  LOOP_H
  0019   940C 000A           jmp   LOOP
  001B   0F0F       TABLE:  .byte  DOT,   S2S        ;DOT=0x0F, S2S=0x0F, H=....
  001C   0F0F               .byte  DOT,   S2S
  001D   0F0F               .byte  DOT,   S2S
  001E   2F0F               .byte  DOT,   C2C        ;C2C=0x2F
  001F   2F0F               .byte  DOT,   C2C        ;E=.
  0020   0F0F               .byte  DOT,   S2S        ;L=.-..
  0021   0F2F               .byte  DASH,  S2S        ;DASH=0x2F
  0022   0F0F               .byte  DOT,   S2S
  0023   2F0F               .byte  DOT,   C2C
  ...
  0040   DF0F               .byte  DOT,   M2M        ;M2M=0xDF
  0041   0000               .byte  EOL,   EOL        ;EOL=0

ARM/Thumb-2

Приведенный ниже код проверялся на оценочной плате STM NUCLEO-F411RE с установленным на ней микроконтроллером STM32F411RET6U. Работа с периферией других микроконтроллеров может быть иной, так что нужно читать документацию.

На плате имеется светодиод, подключеный к пятому выводу порта A, он и будет использован. Внешний светодиод (с токоограничивающим резистором) можно подключить к выводу D13 платы. Используется встроенный RC-генератор c частотой 16 МГц, чтобы его использовать ничего настраивать не нужно.

Для изготовления bin-файла прошивки использовался ассемблер arm-none-eabi-as, компоновщик arm-none-eabi-ld и программа arm-none-eabi-objcopy. В отличие от рассмотренных выше микроконтроллеров файл прошивки не текстовый, он содержит образ того, что будет записано в память микроконтроллера и ничего больше. Прошивка выполняется с помощью установленного на плате программатора ST-LINK/V2-1. При подключении к компьютеру программатор виден как сменный диск, для прошивки нужно скопировать на него подготовленный bin-файл. Если снять две перемычки, программатор можно использовать для прошивки других микроконтроллеров

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

  Адрес      Код        Метка    Мнемоника
  ---------  ---------  -------  ---------
  0800 0000  0202 0000          .word   0x20020000         @SP
  0800 0004  0800 00A7          .word   ENTRY +  1         @Entry_point            @Единица в младшем бите указывает, что набор команд - Thumb
  0800 0008  0800 0059          .word   HNDLR +  1         @NMI_HANDLER
  0800 000C  0800 0059          .word   HNDLR +  1         @HardFault_HANDLER
  0800 0010  0800 0059          .word   HNDLR +  1         @MemManage_HANDLER
  0800 0014  0800 0059          .word   HNDLR +  1         @BusFault_HANDLER
  0800 0018  0800 0059          .word   HNDLR +  1         @UsageFault_HANDLER
  0800 001C  0800 0000          .word   0                  @Reserved
  0800 0020  0800 0000          .word   0                  @Reserved
  0800 0024  0800 0000          .word   0                  @Reserved
  0800 0028  0800 0000          .word   0                  @Reserved
  0800 002C  0800 0059          .word   HNDLR +  1         @SVC_HANDLER
  0800 0030  0800 0059          .word   HNDLR +  1         @DebugMon_HANDLER
  0800 0034  0800 0000          .word   0                  @Reserved
  0800 0038  0800 0059          .word   HNDLR +  1         @PendSV_HANDLER
  0800 003C  0800 0059          .word   HNDLR +  1         @SysTick_HANDLER
  0800 0040  0010 46AA  DOT:    .word   DELAY              @DELAY=0x1046AA         @Константы
  0800 0044  0030 D3FE  DASH:   .word   DELAY *  3
  0800 0048  0010 46AA  S2S:    .word   DELAY
  0800 004C  0030 D3FE  C2C:    .word   DELAY *  3
  0800 0050  0071 EEA6  W2W:    .word   DELAY *  7
  0800 0054  00E3 DD4C  M2M:    .word   DELAY * 14
  0800 0058  E7FE       HNDLR:   b      HNDLR                                      @Обработчик прерываний (пустой)
  0800 005A  480A       INIT:    ldr    R0, [PC, 40]       @ldr R0, HB1E           @Загрузка адреса регистра разрешения тактирования периферии
  0800 005C  2101                movs   R1,  1
  0800 005E  6802                ldr    R2, [R0,  0]
  0800 0060  430A                orrs   R2,  R1
  0800 0062  6002                str    R2, [R0,  0]                               @Включение порта A
  0800 0064  4808                ldr    R0, [PC, 32]       @ldr R0, MR             @Загрузка адреса регистра режима работы порта A
  0800 0066  F240 4100           movw   R1, (1 << (5 * 2))
  0800 006A  6802                ldr    R2, [R0,  0]
  0800 006C  430A                orrs   R2,  R1
  0800 006E  6002                str    R2, [R0,  0]                               @Пятый бит порта A - выход (по умолчанию симметричный, низкоскоростной)
  0800 0070  4806                ldr    R0, [PC, 24]       @ldr R0, ABSR           @Загрузка адреса регистра установки битов порта A
  0800 0072  4907                ldr    R1, [PC, 28]       @ldr R1, ABRR           @Загрузка адреса регистра сброса битов порта A
  0800 0074  2220                movs   R2, (1 << 5)                               @Загрузка маски для установки и сброса пятого бита порта A
  0800 0076  800A                strh   R2, [R1,  0]                               @Сброс пятого бита порта A
  0800 0078  F240 0495           movw   R4,  0x0095        @PAUSE + 1              @Загрузка адреса функции PAUSE
  0800 007C  F6C0 0400           movt   R4,  0x0800
  0800 0080  4770                bx     LR                                         @Возврат
  0800 0082  BF00                nop                                               @Для выравнивания следующих ниже констант по границе слова
  0800 0084  4002 3830  HB1E:   .word   RCC_AHB1ENR        @RCC_AHB1ENR=0x40023830
  0800 0088  4002 0000  MR:     .word   GPIOA_MODER        @GPIOA_MODER=0x40020000
  0800 008C  4002 0018  ABSR:   .word   GPIOA_BSRRL        @GPIOA_BSRRL=0x40020018
  0800 0090  4002 001A  ABRR:   .word   GPIOA_BSRRH        @GPIOA_BSRRH=0x4002001A
  0800 0094  3B01       PAUSE:   subs   R3,  1
  0800 0096  D1FD                bne    PAUSE
  0800 0098  4770                bx     LR
  0800 009A  B500       SIGN:    push  {LR}                                        @Запись в стек адреса возврата
  0800 009C  8002                strh   R2, [R0,  0]                               @Установка пятого бита порта A
  0800 009E  F7FF FFF9           bl     PAUSE                                      @Переход с записью PC в LR
  0800 00A2  800A                strh   R2, [R1,  0]
  0800 00A4  BD00                pop   {PC}                                        @Возврат
  0800 00A6  F7FF FFD8  ENTRY:   bl     INIT                                       @Начало программы
  0800 00AA  F85F 306C  MAIN:    ldr    R3, [PC, -108]     @ldr R3, DOT            @H=....
  0800 00AE  F7FF FFF4           bl     SIGN
  0800 00B2  F85F 306C           ldr    R3, [PC, -108]     @ldr R3, S2S
  0800 00B6  47A0                blx    R4                                         @Косвенный переход с записью PC в LR (в R4 адрес функции PAUSE)
  0800 00B8  F85F 307C           ldr    R3, [PC, -124]     @ldr R3, DOT
  0800 00BC  F7FF FFED           bl     SIGN
  0800 00C0  F85F 307C           ldr    R3, [PC, -124]     @ldr R3, S2S
  0800 00C4  FF7F FFE6           bl     PAUSE
  0800 00C8  F85F 308C           ldr    R3, [PC, -140]     @ldr R3, DOT
  0800 00CC  F7FF FFE5           bl     SIGN
  0800 00D0  F85F 308C           ldr    R3, [PC, -140]     @ldr R3, S2S
  0800 00D4  FF7F FFDE           bl     PAUSE
  0800 00D8  F85F 309C           ldr    R3, [PC, -156]     @ldr R3, DOT
  0800 00DC  F7FF FFDD           bl     SIGN
  0800 00E0  F85F 3098           ldr    R3, [PC, -152]     @ldr R3, C2C
  0800 00E4  FF7F FFD6           bl     PAUSE
  0800 00E8  F85F 30AC           ldr    R3, [PC, -172]     @ldr R3, DOT            @E=.
  0800 00EC  F7FF FFD5           bl     SIGN
  0800 00F0  F85F 30A8           ldr    R3, [PC, -168]     @ldr R3, C2C
  0800 00F4  FF7F FFCE           bl     PAUSE
  ...
  0800 0302  F85F 32B0           ldr    R3, [PC, -688]     @ldr R3, M2M
  0800 0306  FF7F FEC5           bl     PAUSE
  0800 030A  E6CE                b      MAIN

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

Для хранения последовательности знаков и пауз можно использовать массив:

  Адрес      Код        Метка    Мнемоника
  ---------  ---------  -------  ---------
  0800 0000  0202 0000          .word   0x20020000         @SP
  0800 0004  0800 0075          .word   ENTRY +  1         @Entry_point            @Единица в младшем бите указывает, что набор команд - Thumb
  0800 0008  0800 0041          .word   HNDLR +  1         @NMI_HANDLER
  0800 000C  0800 0041          .word   HNDLR +  1         @HardFault_HANDLER
  0800 0010  0800 0041          .word   HNDLR +  1         @MemManage_HANDLER
  0800 0014  0800 0041          .word   HNDLR +  1         @BusFault_HANDLER
  0800 0018  0800 0041          .word   HNDLR +  1         @UsageFault_HANDLER
  0800 001C  0800 0000          .word   0                  @Reserved
  0800 0020  0800 0000          .word   0                  @Reserved
  0800 0024  0800 0000          .word   0                  @Reserved
  0800 0028  0800 0000          .word   0                  @Reserved
  0800 002C  0800 0041          .word   HNDLR +  1         @SVC_HANDLER
  0800 0030  0800 0041          .word   HNDLR +  1         @DebugMon_HANDLER
  0800 0034  0800 0000          .word   0                  @Reserved
  0800 0038  0800 0041          .word   HNDLR +  1         @PendSV_HANDLER
  0800 003C  0800 0041          .word   HNDLR +  1         @SysTick_HANDLER
  0800 0040  E7FE       HNDLR:   b      HNDLR                                      @Обработчик прерываний (пустой)
  0800 0042  4808       INIT:    ldr    R0, [PC, 32]       @ldr R0, HB1E           @Загрузка адреса регистра разрешения тактирования периферии
  0800 0044  2101                movs   R1,  1
  0800 0046  6802                ldr    R2, [R0,  0]
  0800 0048  430A                orrs   R2,  R1
  0800 004A  6002                str    R2, [R0,  0]                               @Включение порта A
  0800 004C  4806                ldr    R0, [PC, 24]       @ldr R0, MR             @Загрузка адреса регистра режима работы порта A
  0800 004E  F240 4100           movw   R1, (1 << (5 * 2))
  0800 0052  6802                ldr    R2, [R0,  0]
  0800 0054  430A                orrs   R2,  R1
  0800 0056  6002                str    R2, [R0,  0]                               @Пятый бит порта A - выход (по умолчанию симметричный, низкоскоростной)
  0800 0058  4804                ldr    R0, [PC, 16]       @ldr R0, ODR            @Загрузка адреса регистра данных порта A
  0800 005A  4905                ldr    R1, [PC, 20]       @ldr R1, ABRR           @Загрузка адреса регистра сброса битов порта A
  0800 005C  2220                movs   R2, (1 << 5)                               @Загрузка маски для установки и сброса пятого бита порта A
  0800 005E  800A                strh   R2, [R1,  0]                               @Сброс пятого бита порта A
  0800 0060  4770                bx     LR                                         @Возврат
  0800 0062  BF00                nop                                               @Для выравнивания следующих ниже констант по границе слова
  0800 0064  4002 3830  HB1E:   .word   RCC_AHB1ENR        @RCC_AHB1ENR=0x40023830
  0800 0068  4002 0000  MR:     .word   GPIOA_MODER        @GPIOA_MODER=0x40020000
  0800 006C  4002 0014  ODR:    .word   GPIOA_ODR          @GPIOA_ODR  =0x40020014
  0800 0070  4002 001A  ABRR:   .word   GPIOA_BSRRH        @GPIOA_BSRRH=0x4002001A
  0800 0074  F7FF FF5E  ENTRY:   bl     INIT                                       @Начало программы
  0800 0078  F240 0394  MAIN:    movw   R3,  0x0094                                @Загрузка адреса массива
  0800 007C  F6C0 0300           movt   R3,  0x0800
  0800 0080  681С       LOOP:    ldr    R4, [R3,  0]
  0800 0082  4324                orrs   R4,  R4
  0800 0084  d0F8                beq    MAIN
  0800 0086  3304                adds   R3,  4
  0800 0088  8805                ldrh   R5, [R0,  0]
  0800 008A  4055                eors   R5,  R2
  0800 008C  8005                strh   R5, [R0,  0]
  0800 008E  3C01       PAUSE:   subs   R4,  1
  0800 0090  D1FD                bne    PAUSE
  0800 0092  E7F5                b      LOOP
  0800 0094  0010 46AA  HELLO:  .word   DOT                                        @DOT=DELAY, H=....
  0800 0098  0010 46AA          .word   S2S                                        @S2S=DELAY
  0800 009C  0010 46AA          .word   DOT
  0800 00A0  0010 46AA          .word   S2S
  0800 00A4  0010 46AA          .word   DOT
  0800 00A8  0010 46AA          .word   S2S
  0800 00AC  0010 46AA          .word   DOT
  0800 00B0  0030 D3FE          .word   C2C                                        @C2C=3*DELAY
  0800 00B4  0010 46AA          .word   DOT                                        @E=.
  0800 00B8  0030 D3FE          .word   C2C
  0800 00BC  0010 46AA          .word   DOT                                        @L=.-..
  0800 00D0  0010 46AA          .word   S2S
  0800 00D4  0030 D3FE          .word   DASH                                       @DASH=3*DELAY
  0800 00D8  0010 46AA          .word   S2S
  0800 00DC  0010 46AA          .word   DOT
  0800 00E0  0010 46AA          .word   S2S
  0800 00E4  0010 46AA          .word   DOT
  0800 00E8  0030 D3FE          .word   C2C
  ...
  0800 01C0  00E3 DD4C          .word   M2M                                        @M2M=14*DELAY
  0800 01C4  0000 0000          .word   EOL                                        @EOL=0

Литература и ссылки

Рейтинг@Mail.ru

Сайт создан в системе uCoz