| Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |
(причем один — неполный), а может быть и шесть и даже больше...
Типичный порт представлен группой из нескольких однобайтовых регистров,
каждый из битов которых соответствуют одному выводу (ноге) контролера.
— регистр направления — "1" — нога работает на выход, "0" — это будет вход
— регистр ввода — какое значение на ноге, такое и считывается из данного бита
— регистр вывода — только если на выход — что сюда записать то и выводится.
— регистр передачи ноги какому либо устройству — если здесь "1" то состояние и
функции данного вывода микросхемы будет определять по своему усмотрению некое
другое связанное с этой ногой устройство (таймер например), а не вышеописанные
три регистра.
— регистр подтяжки — (в новых моделях) подключает резистор, подтягивающий эту
ногу к питанию.
Некоторые порты умеют требовать прерывание. Для них дополнительно:
— регистр флагов прерывания — если "1" — будет требовать (если разрешено)
— регистр разрешения прерывания — разрешает требовать (если "1")
— регистр фронта — определяет по какому фронту на входе (переднему или заднему)
устанавливается флаг прерывания. Следует заметить, что этот механизм работает
совершенно автономно: если прерывание от данной ноги запрещено, при приходе
указанного этим регистром фронта флаг (в регистре флагов) всё равно
устанавливается. И может быть использован для чего-то полезного. А сбрасывать
флаги так и так надо "вручную" (сами они только устанавливаются).
Например подключим к этому порту коллекцию кнопок, сбросим все флаги и
разрешим прерывания. Как прерывание произошло — значит кнопку нажали. Теперь
надо дождаться окончания дребезга: механические контакты имеют такую нехорошую
особенность — замкнул один раз, а она выдала с десяток импульсов... Флаг
сбрасываем, прерывание запрещаем, запускаем таймер. Как таймерный интервал
истёк — смотрим, были ли еще фронты? Если да — значит дребезг еще не кончился,
запускаем таймер по-новой. (А интервал берём в разы больше характерного
интервала дребезга.) Если небыло — меняем фронт на противоположный (чтобы теперь
зафиксировать отпускание) и по-новой разрешаем прерывание...
=========================================================================
Рассмотрим, как организовано расширение адресного пространства в МСП-430.
Расширение до мегабайта (2^20), тоесть теперь адрес стал на 4 бита длиннее
слова, с которым работает процессор. Что для этого сделали:
Во-первых — на четыре бита расширили регистры процессора. (Kроме R2,
который содержит слово состояния процессора (ССП) и соответственно адресом
быть никак не может.) Расширили так же конешно и арифметико-логическое
устройство (АЛУ) и внутренние магистрали процессора... Только снаружи этого
не видно. В результате теперь стало не два вида операндов (байт и слово),
а три: еще и 20-и разрядное значение. Для его обозначения в мнемонике
ассемблерных команд стали использовать буковку А.
Во-вторых — чтобы приспособить уже имеющиеся команды для работы как с
такими вот 20-и разрядными значениями, так и с "дальними", тоже 20-и разрядными
адресами, ввели "префикс" — такую специальную команду, которая сама ничего не
делает, а только указывает следующей после неё обычной команде что она теперь
будет "расширенная". В ассемблерной мнемонике наличие такого префикса
обозначается добавлением после команды буковки X (например не mov, а movx).
Префикс содержит по четыре дополнительных бита к индексу каждого из
операндов, если конешно их методы адресации — индексные. Или к
"непосредственному" операнду — если метод адресации операнда-источника @r0+.
А так же дополнительный бит к имеющемуся в команде признаку размера операнда.
Выглядит это так:
биты 15... ...8 7... ...0
префикс: 0001 1aaa alxx bbbb где aaaa и bbbb — старшие 4 бита
для сравнения ** к операндам AAAA и BBBB
1о-адр.команда: 0001 00kk kraa AAAA (kkk = 0..7) — код операции
2х-адр.команда: KKKK AAAA braa BBBB (KKKK = 4..F) — код операции
Бит l префикса — дополнение к биту r команды, указывающему размер операнда:
при l=1 бит r как и раньше обозначает слово (r=0) или байт (r=1)
при l=0 бит r=1 обозначает 20-и битный операнд, а 00 — зарезервировано.
А биты xx тоже зарезервированы и должны быть 00.
В ассемблере для данного процессора (в отличии, например, от ассемблера
ПДП-11) принято буковку, указывающую размер операнда, писать через точку.
Например mov.w и просто mov — это пересылка слова, а mov.b — пересылка байта.
(По мне — так нагляднее.) Так что теперь эта коллекция обогатилась суффиксом
".a". Но написать mov.a будет неправильно: без префикса сей размер не укажешь!
Надо "movx.a".
Однако, если команда типа регистр-регистр, то оставшиеся не у дел биты
aaaa и bbbb используются по-другому: bbbb указывает сколько раз в дополнение
к первому нужно повторить эту команду. Прямо или косвенно — в зависимости от
младшего из битов aaaa: если он "1" то bbbb это номер регистра, а не сам
счетчик повторений. (В регистре тоже используются только четыре младших бита.)
Еще один из битов aaaa (если "1") велит считать значение признака переноса C
равным нулю. (Что имеет смысл только для команды побитового сдвига, ну и еще
DADD.) А два старших бита поля aaaa так и остались незадействованными.
В третьих — проблема сохранения 20-и разрядных адресов в памяти. И в
частности в стэке при обращении к подпрограмме и при прерывании.
При прервыании, как известно, в стэке сохраняются два слова. Второе — слово
состояния процессора, старший байт которого почти пустой. Вот лишние четыре
бита счетчика команд туда и запихнули. И сохраняются
они теперь всегда.
А вот для подпрограмм так и пришлось вводить "дальний"
вызов сохраняющий оные четыре бита во втором слове. И соответствующую команду
CALLA. Для чего пришлось несколько перекроить две последние одноадресные
команды RETI — возврат из прерывания и NOP — нет операции. (Теперь говорят,
что она якобы была резервная, а в качестве NOP велено использовать MOV #0,R3.)
Они обе отличаются тем, что состоят только из кода операции, а отведенные под
операнд семь бит у них содержат нули. Вот один из этих битов — самый старший,
(бит 6) и заняли под код операции:
биты 15... .. .8. 6 5....0
1о-адр.команды вообще: 0001 — kkk r aaAAAA kkk — код операции = 0..7
команда reti 0001 00 110 0 — -
команда calla 0001 00 110 1 aaAAAA
команда calla 0001 00 111 0 bbBBBB
команда nop 0001 00 111 1 — -
Таким образом команд CALLA — две. У первой из них операнд aaAAAA используется
традиционым образом: AAAA — номер регистра, aa — метод адресации к нему.
Методы адресации — такие же как и во всех прочих командах. Однако, если при
регистровом в счетчик команд заносится 20-битное содержимое указанного
регистра, а при индексном берется из расположенной в памяти таблицы, на начало
которой указывает используемый регистр (и при этом 16-и битный индекс
представляется даже избыточным), то при "непосредственной" адресации @R0+,
когда в счетчик команд заносится константа, идущая за командой следующим
словом — она может быть только 16-и разрядная. Иначе нарушится механика выборки
команд. (Для всех других регистров — то же самое: и индексный и
косвенно-регистровый метод грузят в счетчик команд 20-и разрядный адрес, а
автоинкрементый — только 16-и разрядный.) Поэтому и понадобилась еще одна
команда — у неё BBBB — старшие четыре бита следующей за командой константы,
а методы адресации — свои собственные:
bb = 00 — абсолютный — 20-разрядная константа заносится в R0
01 — относительный — -//— прибавляется к R0
1* — зарезервировано
И наконец в-четвертых под шумок ввели дополнительные команды, прямо не
связанные с расширением адресного пространства. Работающие со значениями в
регистрах, в том числе 20-и разрядными. Это пересылки — MOVA; сохранение
в стеке (и извлечение обратно) группы регистров за один раз — PUSHM/POPM;
арифметические операции ADDA/SUBA/CMPA; и сдвиги (в основном вправо) R**M.
Рассмотрим, как именно они вписаны в пространство команд.
Вспомним, что распределение этого простнаства началось с 2-х адресных
команд, у которых код команды KKKK принимает значения от 4 до 15
биты 15... ...8 7... ...0
2х-адр.команда: KKKK AAAA braa BBBB KKKK = 4..F
1о-адр.команда: 0001 ХХкк кraa AAAA KKKK = 1 ккк = 0..7
команда ветвления: 001k kkss ssss ssss KKKK = 2,3 kkk = 0..7
Таким образом остались незадействованными команды с KKKK = 0 и в одноадресной
команде — два резервных бита ХХ, которые оба должны были быть равны нулю.
Как было указано выше, под префикс расширенной команды заняли ХХ = 1*,
следовательно осталось еще ХХ=01 — это теперь команды PUSHM/POPM.
биты 15... ...8 7... ...0
1о-адр.команда: 0001 00кк кraa AAAA
префикс: 0001 1aaa alxx bbbb
PUSHM/POPM 0001 01pq NNNN RRRR где p=0 — PUSHM, p=1 — POPM
бит q указывает размер (q=0 — 20 бит в двух словах, q=1 — 16 бит в одном)
RRRR — номер регистра — первого из сохраняемых, последнего из
восстанавливаемых а NNNN — их количество. (0000 -> 1 штука)
Команды с KKKK = 0 распадаются на две группы — по значению 7-го бита
и почти все (кроме сдвигов) работают только с 20-и разрядными значениями
биты 15... ...8 7... ...0
0000 AAAA 1pкк BBBB все команды либо Ra->Rb либо #A20->Rb
пересылка 00 mova здесь BBBB номер регистра-приемника Rb,
сравнение 01 cmpa AAAA при р=1 — регистра-источника Ra,
сложение 10 adda а при р=0 — старшие биты 20-разрядной
вычитание 11 suba константы A20
0000 AAAA 0kkk BBBB — почти все команды — MOVA
000 @Ra -> Rb
001 @Ra+ -> Rb
010 &A20 -> Rb
011 E16(Ra) -> Rb
— -сдвиги 10*
Ѓ 110 Ra -> &B20
Ѓ 111 Ra -> E16(Rb)
Ѓ
L-> 0000 NNkk 010r AAAA — команды сдвига операнда в регистре AAAA
rrcm 00 — циклический сдвиг вправо (через бит переноса)
rram 01 — арифметический вправо (знак — размножается)
rlam 10 — арифметический влево (справа вдвигается ноль)
rrum 11 — беззнаковый вправо (слева вдвигается ноль)
Здесь NN — количество разрядов, на которые сдвинуть операнд (1..4)
r — размер операнда: 20 разрядов при r=0 и 16 при r=1
Соответственно в ассемблерной мнемонике этот размер указывается буквой
через точку. Например rram.a r5 для 20-разрядного числа и rram.w для 16.
* * *
С учетом расширенных команд, система команд получилась уже не такой
простой красивой и ортогональной... Но теперь наконец пространство кодов команд
исчерпано почти полностью. Осталось два незадействованных бита в "префиксе",
семь неиспользумых бит в команде RETI, столько же — в бывшей команде NOP.
==============П=Р=И=Л=О=Ж=Е=Н=И=Е========================================
Немножко о том, как устроена память.
С памятью вообще всегда были проблемы. На чем только её не пытались
делать! И на кинескопе от телевизора — заряжая электронным лучем отдельные
точки экрана (или оставляя незаряженными), и на линии задержки в виде трубки,
заполненной ртутью (благо скорость волны в три километра в секунду всё лучше
чем триста тысяч)... Но в конце концов пришли к ферритовым колечкам из
"магнито-твёрдого" материала хорошо сохраняющего остаточную намагниченность.
Материал для них выбирается такой, чтобы кривая намагниченности (т.н. "петля
гистерезиса") была почти прямоугольной. Намагнитить кольцо — элементарно:
пропуская ток в ту или другую сторону через намотанную на него катушку. А вот
определить в какую сторону оно намагничено — посложнее: в кольце магнитный поток
замкнутый — наружу не рассеивается. Но можно сделать так: намотать вторую
катушку, и подав на первую импульс тока попытаться кольцо перемагнитить: если
оно уже было намагничено в эту сторону — эффекта (почти) не будет, а если в
другую — магнитный поток изменится на противоположный и в этот момент во второй
катушке наведётся импульс напряжения.
Далее: берут много колечек, располагают их в виде матрицы (например 64 на 64)
и на каждое наматывать не две, а три катушки — каждая из одного витка: просто
протягивают проволочку через все колечки каждой "строки" матрицы; каждого
"столбца"; и третью — через все — зигзагом по диагонали. С этой третьеё катушки
снимают выходной импульс, а первые две используют для перемагничивания колечек.
Но ток через них пропускают в половину меньше — поэтому перемагничиваются не все
колечки строки или столбца, а только одно, лежащее на их пересечении — то, через
которое пройдут сразу оба этих "полутока". Одна такая матрица — это запоминающее
устройство на один бит. Берут столько матриц, какова длина слова. Всё вместе это
и называется "ферритовый куб".
Колечки брали маленькие — только-только три проволочки просунуть (я видел -
0.8 мм.); перемагничивающие токи — большие (до пол ампера); быстродействие — не
супер (единицы микросекунд). Зато память статическая, а главное -
энергонезависимая. И относительно дешевая — пока микросхемы динамической памяти
не появились.
Это значит было ОЗУ — оперативное запоминающее устройство. ПЗУ тех времён
(постоянное запоминающее устройство с навечно еще на заводе прошитой
информацией) делалось тоже на колечках, но размером куда как по-больше и из
"магнито-мягкого" материала. Колечек брали столько, скольки разрядное слово в
этом ПЗУ; устанавливали их в один ряд; выходная катушка на каждое из них
наматывалась многовитковая, а входных было столько, сколько слов информации надо
было записать. Причем информация в буквальном смысле прошивалась: брали иголку,
вдевали в неё проволочку для очередного слова и протягивали через весь ряд.
Причем если в данном разряде должна была быть единица — проволочку пропускали
через кольцо, а если ноль — мимо. Потом, когда через эту проволочку пропускался
импульс тока — в тех кольцах сквозь которые она была продета в выходной катушке
наводится импульс напряжения. А в тех через которые нет — импульс небыло.
С появлением микросхем постоянных и полу-постоянных запоминающих устройств
больше так не делают. Но термин "прошить" по отношении к ПЗУ — так с тех времён
и остался.
С появлением микросхем сначала "средней" а потом и "большой" степени
интеграции вообще всё стало проще. Потому как вся сложность теперь у них внутри.
То же самое ОЗУ делится на "статическое" и "динамическое".
Статическое память сделана на триггерах. Триггер состоит из двух
логических элементов (инверторов) и требует для своего построения шесть
| Предыдущая глава |
↓ Содержание ↓
↑ Свернуть ↑
| Следующая глава |