Optron #33
20 ноября 1999

Ликбез - Ассемблер взгляд издалека: О блочных командах, работа c портами.

<b>Ликбез</b> - Ассемблер  взгляд издалека: О блочных командах, работа c портами.
       Ассемблер - взгляд издалека

               Продолжение.
  Начало в || 20, 21, 24, 25, 28-30, 32

{}Инфарх, 1999

       Поговорим о блочных командах

  Рассмотрим следующий  пример.  Требуется
перенести блок данных длиной в #1B00 байт,
расположенный  по  адресу  #C000,  в адрес
#4000.
  Программа, выполняющая  такое  действие,
может выглядеть примерно так:

       LD   HL,#C000
       LD   DE,#4000
       LD   BC,#1B00
LOOP   LD   A,(HL)
       LD   (DE),A
       INC  HL
       INC  DE
       DEC  BC
       LD   A,B
       OR   C
       JR   NZ,LOOP
       RET

  Этот фрагмент  для  решения нашей задачи
вполне подходит  в  случае,  если  перенос
должен происходить относительно быстро. Но
если скорость для вас - не главное, то его
можно и укоротить.  А заодно - изучить но-
вую команду ассемблера LDI. Оная выполняет
действия:

      LD   (DE),(HL) ;такой команды на
                     ;самом деле нет у Z80
      INC  HL
      INC  DE
      DEC  BC

  При этом, если содержимое BC равно нулю,
то флаг P/V будет установлен в 0.
  Теперь попробуем   переписать  пример  с
учётом новой информации:

       LD   HL,#C000
       LD   DE,#4000
       LD   BC,#1B00
LOOP   LDI
       JP   PE,LOOP
       RET

  Таким  образом, программа получилась уже
короче.
  Но  разработчики  Z80 не остановились на
достигнутом  и предусмотрели команду LDIR,
предназначенную для переноса целого блока.
Как  и  в предыдущем примере, начало блока
помещается  в регистровую пару HL, длина -
в BC, а адрес, куда произойдт перенос, на-
ходится в DE.
  Изобразим схематически её действие:

LOOP   LDI
       JP   PE,LOOP

  Теперь наш  пример теперь может быть за-
писан так:

       LD   HL,#C000
       LD   DE,#4000
       LD   BC,#1B00
       LDIR
       RET

  Область  экранной памяти в нашем примере
была  выбрана не случайно. Загрузите некий
экранный файл (#1B00 байт) по адресу #C000
и выполните пример. Результат будет нагля-
ден.  Кстати  сказать, таким образом можно
не  только  создавать  экраны, а и чистить
области памяти. Попробуйте:

       LD   HL,#4000
       LD   DE,#4001
       LD   BC,#1800
       LD   (HL),L
       LDIR
       LD   BC,#2FF
       LD   (HL),7
       LDIR
       RET

  Итак, что оно такое? Начало понятно, это
настройка HL на начало экранной памяти. Но
в   DE   помещается  значение  на  единицу
больше,  а  по адресу #4000 помещается "0"
(пробел для экрана). Tеперь начинает рабо-
тать команда LDIR. Хоть она и предназначе-
на для работы с блоками, но перенос проис-
ходит всё равно по одному байту. Таким об-
разом, каждый раз команда будет переносить
в  следующий  адрес  содеримое предыдущего
(0), и так до того момента, пока BC не об-
ретёт нулевое значение.
  Вот  экран  и  очищен.  Но  это касалось
только графической области, остались ещё и
атрибуты.  Вторая  половина  процедуры ис-
пользуется  именно  для  них. Здесь уже не
надо  задавать  значение  для HL и DЕ, оно
осталось  от  первого  LDIR'а. Надо только
задать  длину области атрибутов  #300-1 (а
почему  оно  так  - подумайте сами) и в её
начало  поместить  байт  атрибута.  Мы ис-
пользовали  7, а значит, экран будет иметь
чёрную "бумагу" и белые "чернила".
  А  вот теперь... теперь начинается самое
стр-р-рашное!
  Команды LDI  и  LDIR  - далеко не единс-
твенные для работы с блоками. Есть ещё LDD
и LDDR.
  Но не  волнуйтесь!  Разобрться  с   ними
весьма просто.  Дело в том, что они произ-
водят действия почти полностью аналогичные
командам  LDI  и LDIR, но значения DE и HL
не  увеличиваются, а уменьшаются. Примерно
так:

;команда LDD
       LD   (DE),(HL)
       DEC  HL
       DEC  DE
       DEC  BC

;команда LDDR
LOOP   LDD
       JP   PE,LOOP

  Спросите, зачем оно надо?
  А очень просто!
  Действительно, если  при переносе блоков
они друг друга не перекрывают, разницы ни-
какой   нет.   Но  представьте  себе,  что
"блок-приёмник"  своим  началом  накрывает
окончание "блока-источника". Тогда перенос
методом LDIR повредит информацию.  Выходом
из  данной ситуации и служит команда LDDR.
Просто надо задать в DE и HL адреса блоков
не   начальные,  а  конечные.  Длина,  ес-
тественно, остаётся без изменения.
  Ну, с одним кошамром мы разобрались, те-
перь перейдём к другому. Итак...

             Работа с портами

  Так вот - оказывается, для работы с пор-
тами  тоже есть свои хитрые групповые опе-
рации!
  Для начала  рассмотрим  мутантов команды
IN. Начнём с чего попроще, например, INI:

;пример команды INI
       IN   (HL),(C); (сам придумал)
       INC  HL
       DEC  B

  Достаточно  понятно,  вроде.  Происходит
чтение  из  порта с заданным адресом в ре-
гистр  C,  полученный  байт пересылается в
память по адресу, указанному в регистровой
паре HL, а регистр B страдает от декремен-
та,  в результате чего флаг Z или сбросит-
ся, или установится.
  Теперь посмотрим  на  более  извращённый
вариант:

;пример команды INIR
LOOP   INI
       JR   NZ,LOOP

  Налицо явная аналогия с LDI и LDIR.
  А чтобы  сия аналогия была более полной,
расскажу о командах IND и INDR:

;пример команды IND
       IN   (HL),(C)
       DEC  HL
       DEC  B

;пример команды INDR
LOOP   IND
       JR   NZ,LOOP

  Вот и  все сложности.  Насколько мне ка-
жется,  проблем при освоении этих команд у
вас возникать не должно.
  Но  это  были мутанты команды IN, а есть
ещё и от OUT. Не вдаваясь в пустые рассуж-
дения, сразу приведу их:

          OUTI, OUTD, OTIR, OTDR

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

;пример команды OUTI
       OUT  (C),(HL)
       INC  HL
       DEC  B

;пример команды OTIR
LOOP   OUTI
       JR   NZ,LOOP

;пример команды OUTD
       OUT  (C),(HL)
       DEC  HL
       DEC  B

;пример команды OTDR
LOOP   OUTD
       JR   NZ,LOOP

  Ну, что я говорил? Всё до безобразия по-
нятно. Но если всё-таки вопросы возникнут,
спрашивайте. По мере сил постараюсь на них
ответить.
  Итак,  с групповыми операциями мы разоб-
рались.  Осталось  только, по давней нашей
традиции, поведать...

  О влиянии групповых операций на флаги

  Как всегда, таблица нам в этом поможет.

      ╔═══════════╤═══════════════╗
      ║ Мнемоника │    Флаги      ║
      ║ операции  ├───────────────╢
      ║           │ C Z P/V S N H ║
      ╟───────────┼───────────────╢
      ║   LDI     │ . .  x  . 0 0 ║
      ║   LDD     │ . .  x  . 0 0 ║
      ║   LDIR    │ . .  0  . 0 0 ║
      ║   LDDR    │ . .  0  . 0 0 ║
      ║   INI     │ . x  ?  ? 1 ? ║
      ║   IND     │ . x  ?  ? 1 ? ║
      ║   INIR    │ . 1  ?  ? 1 ? ║
      ║   INDR    │ . 1  ?  ? 1 ? ║
      ║   OUTI    │ ? x  ?  ? 1 ? ║
      ║   OUTD    │ ? x  ?  ? 1 1 ║
      ║   OTIR    │ ? 1  ?  ? 1 ? ║
      ║   OTDR    │ ? 1  ?  ? 1 ? ║
      ╚═══════════╧═══════════════╝

  А вот теперь действительно всё... на се-
годня. А вообще-то нам с  вами  ещё  долго
предстоит "Учиться,  учиться,  и учиться".
Но это потом, а пока - до свидания!

          Продолжение следует...

              ──══════════──


           
           
           
           




Другие статьи номера:

ZX-Net - Эхо-конференция SPBZXNET.GAMES.

ZX-Обоз - Обзор электронной прессы: Полесье 13, Plutonium 14, ZX-Humor 3, Nicron 114, Wallpaper 7.

Железо - К вопросу об адресации портов ZX Spectrum.

Знакомьтесь - Владимир Булчукей (Wlodek Black)

Ликбез - Ассемблер взгляд издалека: О блочных командах, работа c портами.

Реклама - Реклама и объявления...

Стихи - Приход смерти.


Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Вступление - От авторов.
Обратная связь - контакты редакции.
Металлолом - Из истории Betadisk'а: Дисковый интерфейс от Technology Research был.
Перспектива - "Hellraizer" (по мотивам книги А.Нортона "Королева Солнца").
Интервью - интервью с Вячеславом Медноноговым на тему Черного Ворона 2 и 1 и НЛО 2.

В этот день...   21 ноября