| Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |
после чего общаясь с внешним загрузчиком по последовательной линии связи (типа
ком-порта) может стереть одну страницу или всё ЭППЗУ, записать туда нечто
переданное ей снаружи, но так-же и считать и передать наружу что сейчас в памяти
находится. Только она требует пароль, в качестве которого ей надо предъявить
содержимое таблицы векторов. (Ну типа кто прошлый раз туда всё это писал -
должен знать.) А без этого — только стирает всё ЭППЗУ, после чего резко добреет
и уже дозволяет делать что угодно.
Но это так сказать "аварийный механизм" — обычно программируют этот
контроллер с помощью т.н. интерфейса JTAG, каковой позволяет так-же лазить в
регистры процессора и внешних устройств; запускать и останавливать программу,
прогонять её по шагам... Но у него есть плавкий предохранитель — его можно
пережечь и тогда JTAG блокируется. (Типа всё — отладка закончена.)
А вообще перепрошить ЭППЗУ может любая программа, а вовсе не только
специально на то уполномоченная. Среди устройств у любого, даже самого младшего
микроконтроллера этого семейства обязательно есть устройство управления
флеш-памятью. С помощью которого можно стирать страницы ЭППЗУ и/или писать туда
что угодно... Ежели конешно питающее напряжение два вольта или больше... Ну и
аккуратно надо это делать — буквально ходить на ципочках: все прерывания
запретить, в ЭППЗУ зря не лазить — код перенести куда нибудь в другое место
(да хоть в ОЗУ)... В начале ЭППЗУ есть две маленькие странички — специально
чтобы туда данные можно было писать — ну те, которые должны сохраняться после
отключения питания. А так — страницы ЭППЗУ довольно большие.
Напомню, что ЭППЗУ флеш-типа пишется пословно, а вот стирается — только
сразу вся страница. При стирании все биты сбрасываются в "0", а при записи
некоторые из них устанавливаются в "1".
Аналог системной магистрали, к которой в PDP-11 подключены все входящие в
систему устройства, в MSP-430 если и есть, то не афишируется. По крайней мере
наружу никакой магистрали для подключения внешней памяти или еще чего-то
подобного (как у других аналогичных контроллеров) не выходит. Система полностью
закрытая.
Как организованы прерывания — тоже неизвестно, но внешне всё выглядит почти
как в PDP-11: одно устройство — один вектор; вектор — одно слово — адрес
подпрограммы, которая должна обслуживать данное устройство. В слове состояния
процессора 1 бит — разрешение прерываний. Если он ноль — ни на какие требования
прерываний процессор не реагирует. У каждого устройства где нибудь в самом
главном управляющем регистре есть два бита: признак готовности — указывающий что
надо бы это устройство обслужить и разрешение прерывания, разрешающее ему в
случае готовности это самое прерывание требовать. (По фиксированному вектору,
разумеется.) Ещё там как правило есть битик, включающий это устройство (ну или
выключающий нафиг — чтобы лепестричесво не потребляло). Ежели устройство
включено, готово и прерывание ему требовать разрешено — требует. Ежели в ССП
процессора прерывание тоже разрешено — оно и происходит. Но признак готовности
как правило сам не сбрасывается — его должна сбросить запущенная по прерыванию
программа. А то после выхода устройство потребует прерывания заново. Хотя
устройства сильно разные...
Например у сильно вумного 12-и разрядного АЦП есть кольцевой буфер для
результатов преобразования, состоящий из 16 ячеек. И к каждой ячейке — признак,
указывающий что АЦП, запскающееся само собою — от таймера, в эту ячейку уже
чего-то положило, а процессор это оттуда еще не взял. Т.е. сбрасывающийся
автоматически — при считывании из ячейки. Ну так АЦП (если разрешено) требует
прерывания если хоть один из этих признаков установлен. А разрешение — для
каждого признака персонально. (Так, чтобы зря не дергать программу — можно
например разрешить только каждый четвертый и забирать за раз по четыре слова.)
Процессор — типичная регистровая машина, как и PDP-11, только регистров
здесь не 8 а 16. Первые четыре используются для специальных целей, остальные -
самые обычные.
Как уже говорилось: R0 — счетчик команд, R1 — указатель стэка. А вот через
R2 доступно слово состояния программы (ССП). Кроме всё тех же самых признаков
NZVC (правда несколько в другом порядке) и признака разрешения прерывания, ССП
содержит четыре бита, напрямую управляющих тактовыми генераторами, а так же
подачей тактовых импульсов на ЦП и на периферийные устройства. Команды СТОП у
этой машины нет — за ненадобностью: установила программа в единичку
соответствующий бит (управляющий подачей тактовых импульсов на процессор) -
процессор остановился. А коли прохождение их на периферийные устройства не
запретила — таймер продолжает тикать. Как дотикает — потребует прерывания. При
прерывании ССП обнулилось (после сохранения его старого содержимого в стэке) -
прохождение тактовых импульсов на процессор разрешилось — программа пошла. Как
дошла до возврата из прерывания — в R2 записалось из стэка то что там раньше
было. А там в соответствующем бите единичка — тактовые импульсы на процессор
не поступают, программа опять стоит...
А регистр R3 — фиктивный. Его как такового просто нет... Впрочем не будем
забегать вперёд.
Самое интересное — это несомненно система команд. Здесь она настолько
маленькая и простая, что у меня даже слов нет. Так как здесь всё по шестнадцать,
то естественная для данной машинки система счисления — шестнадцатеричная.
Соответственно команда разбита на группы по четыре бита, каждая из которых
обозначается одной шестнадцатеричной цифрой. (Кто вдруг не знает: первые десять
цифр — обычные десятичные, а недостающие шесть — латинские буквы A..F.)
Ну так вот: команда, как и у PDP-11 занимает шестнадцатиразрядное слово.
Система команд тоже двухадресная; адресация операндов тоже через регистры,
только методов адресации куда как поменьше. (Зато регистров в два раза больше.)
2-х адресная команда (по битам) выглядит так: КККК АААА браа ББББ,
где: номера битов 15... ...8 7... ...0
КККК — код команды байты старший младший
АААА — первый операнд — "источник"
ББББ — второй операнд — "приёмник" — в него записывается результат
б — метод адресации для операнда Б — всего один бит (увы) — Rx или E(Rx)
аа — метод адресации для операнда А — тоже (увы) всего два бита
р — размер операнда — если 0 — целое слово, если 1 — байт.
Таким образом для операнда-приёмника всего два метода адресации: либо
регистровый, либо индексный. Для операнда-источника — чуть побольше (но тоже
никаких особо косвенных): 00 — Rx, 01 — E(Rx), 10 — (Rx) и 11 — (Rx)+.
Индекс Е, как и в PDP-11 — второе или третье слово команды.
А вот на второй (ССП) и третий (фиктивный) регистры эти методы адресации
действуют особым образом: совершенно очевидно, что лазить непосредственно в ССП
имеет смысл (ну например напрямую установить или сбросить какие хочешь признаки -
никаких особых команд для этого не надо!), а вот использовать его содержимое в
качестве адреса — абсурд. За сим сделано так:
— регистровый метод адресации по отношению к R2 работает как обычно
— а вот индексный считает что там — ноль, т.е. получается абсолютная адресация.
Все остальные методы адресации применительно к R2 и к R3 дают "литералы" -
короткие константы (используемые в программе наиболее часто): 0, 1, 2, 4, 8, -1.
R3 -> #0
E(R3) -> #1 — этой команде второго слова не причитается
(R3) -> #2 (R2) -> #4
(R3)+ -> #-1 (R2)+ -> #8
А все остальные константы, как и в PDP-11, получаются с помощью известного
программного фокуса-покуса (R0)+ (или, что то же самое @R0+).
Сразу обратим внимание: с одной стороны существенно более бедный по сравнению
с ПДП-11 набор методов адресации заставляет использовать несколько команд там,
где в той же ПДП-11 хватало одной. В том числе чтобы обратиться по адресу,
лежащему в оперативной памяти, надо сперва затащить его в регистр. (Благо
регистров здесь в два раза больше.) Но с другой стороны это же обстоятельство
позволило расширить адресное пространство, просто увеличив размеры регистров.
В то время, как в ПДП-11 подобный фокус невозможен как раз из-за наличия сильно
косвенных методов адресации.
Двухадресных команд — 12 штук (коды 0..3 — для расширения системы команд)
4 0100 MOV A,B — пересылка A -> B или B=A
5 0101 ADD A,B — сложение A+B -> B или B+=A
6 0110 ADDC A,B — сложение с переносом A+B+C -> B или B+=A+C
7 0111 SUBC A,B — вычитание с переносом ~A+B+C -> B или B-=A+C
8 1000 SUB A,B — просто вычитание ~A+B+1 -> B или B-=A
9 1001 CMP A,B — сравнение (B-A)?
A 1010 DADD A,B — сложение с 10-ым дополнением [A+B+C] -> B ???
B 1011 BIT A,B — сравнение побитовое (A&B)?
C 1100 BIC A,B — сброс битов (НЕ-И) ~A&B -> B или B&=~A
D 1101 BIS A,B — установка битов (ИЛИ) A|B -> B или B|= A
E 1110 XOR A,B — инверсия битов (искл.ИЛИ) A^B -> B или B^= A
F 1111 AND A,B — просто побитовое (И) A&B -> B или B&= A
Как видим, кодов хватило на всё, даже на десятичное сложение (которое лично я
ни разу в жизни так ни для чего и не использовал). Но команд, не вписывающихся в
концепцию "операция за один такт", таких как умножение и деление, здесь нет.
Заметим: в команде CMP операнды вычитаются так же, как и в команде SUB,
разве что результат нигде не сохраняется. В аналогичной команде ПДП-11 порядок
вычитания операндов — обратный.
Для умножения в тех моделях, которые по-старше, предусмотрено отдельное
устройство — аппаратный умножитель: в один регистр засовываешь первый операнд, в
другой — второй, и через пару тактов можно считывать 32-х разрядный результат.
Причем это устройство выполняет не просто умножение, а (при желании) еще и
умножение с накоплением — операция, весьма востребованная во многих алгоритмах
(например при цифровой фильтрации) — перемножить множество пар чисел и все
результаты сложить.
А вот деление — увы — так и приходится при необходимости делать вручную. Про
операции с плавающий запятой никто даже и не заикается — в тех областях
применения под коие заточен сей контроллер, нужны они как собаке пятая нога.
(Кошек за хвост на бегу хватать.)
Под все остальные команды выделены коды 0..3, но задействованы не все:
Кодов команд с первой цифрой 0 в базовом наборе нет (оставлены для расширения);
Одноадресные команды — цифра 1 (но два бита в коде операции незадействованы);
команды ветвления — цифры 2 и 3, точнее первые три бита 001, следующие три — код
операции, и оставшиеся десять — смещение со знаком (расстояние, на которое надо
перейти).
Одноадресных команд — 8 штук. Их коды (по битам): 0001 -КК Крaa АААА,
где: номера битов 15... ...8 7... ...0
— — незадействованные биты (оставлены для расширения, должны быть = 0)
ККК — код операции
АААА — номер регистра для единственного операнда
aa — его метод адресации
р — его размер (0 — слово, 1 — байт)
ККК
000 RRC A — циклический сдвиг вправо (такой же в точности как в PDP-11)
001 SWPB A — обмен байтов в слове
010 RRA A — арифметический сдвиг вправо (такой же в точности как в PDP-11)
011 SXT A — расширение знака ( -//— )
100 PUSH A — положить на стэк A -> -(R1)
101 CALL A — переход к подпрограмме R0 -> -(R1); A -> R0
110 RETI — возврат из прерывания (R1)+ -> R2; (R1)+ -> R0
111 NOP — нет операциии
Так как декрементного метода адресации нет — пришлось вводить отдельную
команду PUSH чтобы положить что либо на стэк; особой команды POP не требуется:
эту функцию успешно выполняет MOV (R1)+, XXX. Она же (в форме MOV (R1)+,R0)
заменяет команду возврата из подпрограммы. А вот возврат из прерывания, где
приходится вытаскивать из стэка два слова — отдельная команда. Сдвиги — только
вправо (к младшим разрядам), потому что функции сдвигов влево (к старшим)
успешно выполняет команда ADDC A,A, или для арифметического сдвига, при котором
бит C задвигать в младший разряд не надо — просто ADD. Правда с сохранением
знакового разряда некоторые проблемы — но ничего не поделаешь — нет в мире
совершенства.
Признаки результата NZVC располагаются в ССП (он же R2) не совсем как в
PDP-11: — — П-Т NZVC в младшей модели, где только 1 бит приоритета П
— — V
* * *
ПNZC здесь
* * *
— биты управляющие тактовыми сигналами
Т.е. не самый нужный признак переполнения V вынесен в старший байт — для
того, чтобы в число первых четырёх попал признак П — разрешения прерывания.
(Напомню, что короткие константы (литералы) у нас только до восьми, т.е.
позволяют достать только четыре младших бита.) И еще, в отличии от PDP-11 -
команды MOV, BIC и BIS признаков не изменяют — чтобы можно было использовать
их для изменения этих же признаков напрямую (обращением прямо в R2) не опасаясь
неожиданных последствий.
Используются признаки — в точности так-же как и в PDP-11 — командами
ветвления, каковых здесь восемь штук. (В PDP-11 было 7 пар условных
переходов и один безусловный — всего пятнадцать.)
Команда ветвления по битам выглядит так: 001К ККSS SSSS SSSS,
где: номера битов 15... ...8 7... ...0
SS...SS — смещение (кол-во слов, на которые надо перейти) число со знаком
ККК — код команды:
000 JNZ или JNE ветвление если Z==0 т.е. если А!=Б
001 JZ или JEQ Z==1 А==Б
010 JHS или JNC C==0 А< Б для чисел без знака
011 JLO JC C==1 А>=Б -//-
100 JN N==1 если число отрицательное
101 JGE (N^V)==0 А>=Б для чисел со знаком
110 JL (N^V)==1 А< Б -//-
111 JMP безусловный переход
Как видим: команд ветвления куда как по-меньше, т.е. в наличии действительно
только самые необходимые. Например команд в чистом виде проверяющих состояние
признака V — нету — его, если очень припечет, придётся проверять на общих
основаниях (например командой BIT #0x100) и ветвиться уже по признаку Z.
Команда JMP здесь — полный аналог команды BR у PDP-11, а аналога ейной команды
JMP нету за ненадобностью — эту функцию успешно выполняет команда MOV XXX,R0.
Ну-с, можно подвести некоторый итог: 12 двухадресных команд, 8 одноадресных и
8 команд ветвления — всё, других команд у этой машины просто нет!
Внешних устройств у этой машины довольно много, все разные. Выделить
"типичное" пожалуй что не представляется возможным... Хотя самое простое, это
пожалуй порт ввода/вывода.
Этот самый порт — всего лишь восемь ног микросхемы — процессор может ими
управлять по своему усмотрению. Таких портов у контроллера может быть всего два
| Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |