23 апреля 1998 |
|
╔══════════════════════════════════════════════════════════════╗ ║ Кодинг. ║ ╙──────────────────────────────────────────────────────────────╜ (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 ...
Other articles:
|
|
|
|
|
|
Similar articles:
В этот день... 23 November