Proton #30
23 апреля 1998

Кодинг - На этот раз я расскажу о выводе на экран 64 символов в строке.

<b>Кодинг</b> - На этот раз я расскажу о выводе на экран 64 символов в строке.
╔══════════════════════════════════════════════════════════════╗
║           Кодинг.              ║
╙──────────────────────────────────────────────────────────────╜
(C) EVP-SOFT

   Всем  привет. После долгого перерыва снова вышла рубрика "Ко-
динг.".  На  этот раз я расскажу о выводе на экран 64 символов в
строке.
   Все  ассемблерные  тексты в формате ALASM'а. И если какой-ни-
будь  там  GENS  не  переваривает команду вроде LD A,LX, DUP или
INCBIN, то не надо звонить мне с вопросами типа 'чем эту команду
заменить?', а просто надо ставить 512 кб и переходить на ALASM.

   Для  начала  подготовим  фонт.  Для повышения скорости вывода
фонт  надо из обычного формата (когда 8 байт каждого символа ле-
жат  друг за другом) конвертировать в "треть экрана", т.е. чтобы
между байтами одного знака было смещение #100. Тогда адрес знака
будет вычислятся так:
        LD      H,0
        LD      L,код символа
        LD      BC,FONT
        ADD     HL,BC
в HL теперь первый байт, для следующего просто делаем INC H
   А  если  не  сконвертировать фонт, то тогда код знака сначала
надо умножить на восемь - а это лишние 33 такта:
        LD      H,0
        LD      L,код символа
        LD      BC,FONT
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,HL
        ADD     HL,BC
в  HL  теперь первый байт, для следующего делаем INC HL, но если
фонт расположить по адресу, кратному 8, то можно INC L
   Ну а конвертируется фонт такой вот процедурой:
        ORG     #6400,0
        LD      HL,#8000
        LD      DE,#4000
        LD      BC,256
M1      PUSH    HL
        PUSH    DE
        PUSH    BC
        LD      B,8
M2      LD      A,(HL)
        LD      (DE),A
        INC     L
        INC     D
        DJNZ    M2
        POP     BC
        POP     DE
        POP     HL
        DEC     BC
        INC     E
        DUP     8
        INC     HL
        EDUP
        LD      A,C
        OR      B
        JR      NZ,M1
        RET
        ORG     #8000,0
        INCBIN  "FontбЧ.C" ;подгрузка обычного фонта
   Ассемблируем,  потом вызываем STS. Там делаем CALL #6400, за-
тем сохраняем полученный фонт командой SAVE "64$0.C" #4000,#800.

   Есть  несколько вариантов печати. Можно хранить каждый символ
в  старшем  полубайте, а потом, если вывод нечётный, то сдвигать
его  в помощью RRCA. Или можно в младшем полубайте хранить копию
старшего,  а перед выводом отбрасывать ненужную половину по мас-
ке. Но самый быстрый способ вывода - это иметь в памяти два фон-
та,  один  в  старших полубайтах, а младшие пустые, второй соот-
ветственно наоборот.
   Однако  в  теле  программы, для лучшей упаковки, надо хранить
только один фонт, а второй создавать перед запуском:
FNT_EXT LD      HL,FONTO ;адрес фонта
        LD      DE,FONT1   ;адрес копии
        LD      BC,#800  ;счётчик
FNT1    LD      A,(HL)     ;берём байт
        RLCA             ;сдвигаем старший полубайт в младший
        RLCA             ;
        RLCA             ;
        RLCA             ;
        LD      (DE),A     ;кладём результат
        INC     HL       ;адреса следуюших
        INC     DE       ;байт
        DEC     BC         ;уменшаем счётчик
        LD      A,C      ;если в BC ещё
        OR      B        ;не ноль то
        JR      NZ,FNT1  ;повтор цикла
        RET              ;иначе возврат
FONTO   INCBIN  "64$0.C"  ;фонт имеющийся
FONT1   DEFS    #800     ;а тут будет второй фонт.

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

  Эта процедура получает в HL начало строки, и печатает её, пока
не  встретит  код CR (#0D), если строка короткая, то добивает её
пробелами. При выходе в HL следующий после CR адрес. Итак:

PRINT   EX      DE,HL  ; сохраним адрес текста
        LD      A,32      ;установим счётчик пустых знакомест
        LD      (PRT_X),A ;

  Теперь вычислим координаты на экране. В COORD_Y заносим верти-
кальную  позицию,  а  в COORD_X - горизонтальную. Но на практике
обычно  горизонтальная  позиция  равна 0, и тогда блок обработки
COORD_X  можно  исключить. Младший бит COORD_X должен быть равен
0, т.е. X-адрес только нечётный:

        LD      A,0
COORD_Y EQU     $-1
        LD      B,A
        AND     #07
        RRCA
        RRCA
        RRCA
;        LD      C,0
;COORD_X EQU     $-1
;        SRL     C
;        OR      C
        LD      L,A
        LD      A,B
        AND     #18
        OR      #40
        LD      H,A
        LD      (PRT_WR),HL  ;сохраним адрес знакоместа

  Берём два знака для печати:

        EX      DE,HL  ; возвращаем в HL адрес текста

PRTS    LD      A,(HL) ; берём знак
        INC     HL      ; это на будущее
        CP      #A
        JP      Z,PRTS ; код LF игнорируем
PRT1    CP      #D
        JP      Z,PRT18 ; нашли код CR - конец строки

        LD      E,A   ; сохраним первый символ в E

PRT7    LD      A,(HL) ; берём второй знак
        INC     HL
        CP      #A
        JP      Z,PRT7 ; игнорируем LF
        CP      #D
        JP      NZ,PRTЧ  ; если это не CR, то начинаем печать

PRT13   DEC     HL   ; а если CR - то оставим его на первый цикл

        LD      A,#20 ; ну а пока выведем пробел

PRTЧ    PUSH    HL  ; сохраним адрес текста

        LD      L,A ;и начнём вычислять адреса символов в фонте
        LD      H,0
        LD      BC,FONT1
        ADD     HL,BC    ; вычислим второй(т.е. правый) символ
        EX      DE,HL     ; в DE будет адрес второго символа
        LD      H,0       ; а в HL скоро появится первый
        LD      BC,FONTO
        ADD     HL,BC    ; вычислим первый(т.е. левый) символ

        LD      BC,0   ; в BC заранее подставили адрес печати
PRT_WR  EQU     $-2    ; посредством метки PRT_WR
        LD      A,C        ; это на будущее, следующий адрес
        INC     A          ; печати, т.к. автоперевода строк тут
        LD      (PRT_WR),A ; нет, то нам нужен только один байт

        DUP     8  ; сделаем раскладку
        LD      A,(DE) ;берём второй символ
        OR      (HL)    ;на него накладываем первый
        LD      (BC),A ;и всё это кладём уже на экран
        INC     H   ;находим адреса следующих
        INC     D   ;байт этих символов
        INC     B    ;переходим на следующую линию экрана
        EDUP       ; конец раскладки
        ORG     $-3 ; затрём 3 посл. команды посл. раскладки
                    ; т.к. они в ней ненужны.

PRT15   LD      A,0       ; счётчик пустых знакомест,
PRT_X   EQU     $-1       ; вначале тут будет подставлено 32
        DEC     A         ;
        LD      (PRT_X),A ;

        POP     HL      ;восстановим адрес текста
        JP      PRTS    ;и начнём вывод следующих двух символов

  А  это процедура добивает пробелы в конце строки, очень полез-
но, если снизу уже что-то было. Если это не надо, то просто уби-
раем  всё  что  связано  со  счётчиком пустых знакомест и меткой
PRT_X,  и  где около метки PRT1 стоит JP Z,PRT18 вместо этого JP
ставим RET Z. А иначе набиваем дальше:

PRT18   LD      A,(PRT_X) ;проверим наличие
        AND     A         ;пустых знакомест
        RET     Z         ;если нет, то возврат

        PUSH    HL        ;иначе сохраним адрес текста

        LD      E,A       ;в E будет кол-во знакомест для чистки
        XOR     A
        LD      HL,(PRT_WR) ;адрес на экране
        LD      B,8       ;высота знакоместа конечно 8 линий
PRT10   PUSH    HL
        PUSH    BC
        LD      B,E
PRT9    LD      (HL),A
        INC     L
        DJNZ    PRT9   ;цикл очистки одного знакоместа 8x8(!)
        POP     BC
        POP     HL
        INC     H
        DJNZ    PRT10 ;цикл очистки оставшихся знакомест

        POP     HL   ;восстановим адрес текста
        RET         ;и возврат

  Вот  в  качестве  примера процедура 'LINE', которая выводит на
экране сверху и снизу две полоски из символов "*":

LINE    XOR     A
        LD      (Y),A
;        LD      (X),A   ;;;; смотри COODR_X
        LD      HL,LIN1     ;
        CALL    PRINT       ;
        LD      A,23        ;
        LD      (Y),A       ;
;        XOR     A       ;;;;
;        LD      (X),A   ;;;;
        LD      HL,LIN1
        CALL    PRINT
        RET
LIN1    DEFS    64,"*"
        DEFB    #D



  Ну и раз уж начали тему вывода 64 символов, то сейчас я приве-
ду  пример  и  под IS-DOS. А именно новый драйвер 64 символов, в
отличии  от стандартного "tyбЧ.typ" этот будет печатать всю таб-
лицу из 256 символов.

  Начнём с теории. Драйвер, как и резидент, должен иметь в конце
слово  #FFFF, после которого лежит таблица адресов, которые надо
настроить  при  инсталяции  (это  делает set.com). Иначе, если в
драйвере  есть  команды JP nn, LD a,(nn), LD HL,nn то его нельзя
будет  перемещать в памяти и система просто зависнет. Причём ад-
реса в таблице на единицу меньше реальных, это сделано для упро-
шения настройки команд тима JP nn, LD A,(nn) и аналогичных.

  В начале драйвера должна быть следующая таблица:
 DEFW адрес инсталляции, если 0 то не вызывается
 DEFW адрес ПП вывода символа на экран, входные данные: A - код
      символа, DE' - адрес на экране, а левый или правый надо
      считать самим. Выход: если был правый символ, то E'+1
 DEFW адрес ПП управления инверсией: A:Z - нету, A:NZ - есть
 DEFW адрес ПП установки координат, вход: BC - лог.позиция,
      выход: DE' - адрес на экране, левый или правый символ -
      запомнить в драйвере.
 DEFB длина курсора в пикселях, это в данном случае 4.
 DEFW физ. координаты
 DEFW лог. координаты
 DEFB тип: 0-экран/1-принтер
 DEFW адрес ПП обработки ошибок.


  Итак, начнём создавать драйвер.
;
; Драйвер 64 символов в строке
; Под IS-DOS
; (C) EVP-SOFT at 1998.04.12
;

        ORG     50000

        DEFW    0          ; эта стандартная таблица,
M5      EQU     $-1        ; описание смотри выше.
        DEFW    TTYOYT     ;
M6      EQU     $-1        ;
        DEFW    PRCPL      ;
M7      EQU     $-1        ;
        DEFW    PRADD      ;
        DEFB 4,0,0,0,0,0   ;
M13     EQU     $-1        ;
        DEFW    M12        ;


  Для  ускорения  печати  фонт будет в "экранном формате" (см. в
предыдущей  статье).  Но только надо будет старший полубайт про-
дублировать  в  младший,  т.к. в IS-DOS'е памяти нехватит, чтобы
иметь два раздельных фонта.

FONT    INCBIN  "64$0&1.C"

  Управление инверсией:

PRCPL   OR      A
        JR      Z,M4
        LD      A,#2F  ;#2F - это код команды CPL
M4      LD      (M3),A
M12     XOR     A ;а сюда при случае будем передавать обработку
        RET       ;ошибок. Т.е. просто их игнорировать

  А тут вычисляем координаты печати.

PRADD   SRL     C
        SBC     A,A     ; определяем
        XOR     #F0     ; левый или правый символ
M9      LD      (M1),A  ; в знакоместе 8x8
        LD      A,B
        AND     #07
        RRCA
        RRCA
        RRCA
        OR      C
        LD      E,A
        LD      A,B
        AND     #18
        OR      #40
        LD      D,A
        EXX       ; теперь в DE' будет адрес на экране
        RET       ; и можно возвращаться

  Теперь дошла очередь и до ПП вывода на экран:

TTYOYT  EXX
        LD      H,0
        LD      L,A
M10     LD      BC,FONT
        ADD     HL,BC
        EX      DE,HL
        LD      BC,#0800 ; в B счётчик цикла
M1      EQU     $-2    ; в C маска выбора "левый или правый"
M15     LD      A,(DE)  ;;
M3      NOP       ;в случае инверсии сюда заносим #2F, т.е. CPL
        AND     C       ;;
        XOR     (HL)    ;;
        AND     C       ;; ну тут всё как обычно.
        XOR     (HL)    ;;
        LD      (HL),A  ;;
        INC     D       ;;
        INC     H       ;;
        DJNZ    M15
        LD      A,H   ; восстановим начальный адрес
        SUB     8     ;
        LD      D,A   ; и вернём его в D, потом это будет D'
        LD      A,C     ; сменим маску с левого на правый или
        CPL             ; наоборот
M8      LD      (M1),A  ;
        RLA           ; если с правого на левый, то
        LD      A,0   ; надо перейти к следующему
        ADC     A,L   ; знакоместу
        LD      E,A   ; кладём результат в E
        EXX       ;теперь DE станет DE', а остальное неважно
        RET

  Ну и теперь таблица адресов, где была прямая адресация:

        DEFW    #FFFF ; признак таблицы
        DEFW    M4,M5,M6,M7,M8,M9,M10,M13 ;адреса-1, а проще
                                          ;говоря, адреса команд

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

  ... этот драйвер можно скачать на HARD BBS ...



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

BSS - Сетевые новости. ZX-Net 095, Независимые BBS.

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

Кодинг - На этот раз я расскажу о выводе на экран 64 символов в строке.

Юмор - Анекдоты.

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

От авторов - Редакция.


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

Похожие статьи:
Особенности - Особенности работы с жестким диском в подразделах TR-DOS.
Юмор - Анекдоты.
Gamez - описание новой игры Сталкер.
AD&D - Тексты на тематику AD&D.
FREAKS - Про халявную энергетику.

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