Печать текстовой строки шрифтом 8х8 с/без атрибутов

Материал из SpeccyWiki
Перейти к: навигация, поиск

Для вывода текста необходимо знать расположение данных шрифта, хранящихся в ПЗУ ZX Spectrum: порядковое расположение соответствует кодам ASCII.Каждый символ описывается блоком данных размером 8 байт, таким образом любой символ представлен 8х8 точек. Например, символ 'X' выглядит как: Двоичные данные:

00000000
01000010
00100100
00011000
00011000
00100100
01000010
00000000

все 96 символов располагаются по адресу #3D00, для печати на экран удобнее всего скопировать 8 байт, описывающих символ на экран:

Входные данные процедуры printtext: DE=адрес вывода на экран, HL=адрес сообщения, используется BC.

        ORG #8000
;-1
   ld de,#4000
   ld hl,message1
   call printtext
;-2
   ld de,#4021
   ld hl,message2
   call printtext
;-color
   ld hl,#5800
   ld ix,message3
   call printattrtext

stu: jr stu

printtext
m11:
  ld a,(hl);получиnь первый код символа
  inc hl
  or a;для завершения печати используется трюк: текст ограничен байтом 0, который не используется
  ret z;таким образом не надо вычислять и определять длину сообщения
  push hl;перед вычислением адреса данных символа HL нужно запомнить
  ld l,a
  ld h,0; все данные в шрифте занимают 8 байт, легче  будит умножить код символа на 8
  add hl,hl;hl=hl+hl или hl*2
  add hl,hl;hl*4
  add hl,hl;hl*8
  ld bc,#3C00;адрес шрифта ;1
  add hl,bc;hl=адрес данных необходимого символа;1

;!  ld a,h;для сохранения регистра BC
;!  add a,#3C;удобнее заменить команды, помеченные ;1 на команды с меткой;!
;!  ld h,a

  push de;сохранение адреса DE
  dup 8; операция выполняется 8 раз
  ld a,(hl);Данные шрифта
  ld (de),a;копируются на экран
  inc hl;следующие данные
  inc d;вниз на линию в экране
  edup;операция завершена
  pop de
  inc de; восстановлен адрес DE из стэка и переход к следующему знакоместу
  pop hl;восстановлен адрес сообщения в HL
 jr m11; переход к циклу печати

С печатью текста с помощью аттрибутов экрана процедура выглядит сложнее. Для вывода текста нужно побитно выполнить тест над восемью байтами и заполнять экран в зависимости от результата теста Входные данные:HL=адрес экранной памяти,IX=сообщение.используется BC,DE

printattrtext

m1:
 ld a,(ix)
 or a
 ret z; если код сообщения 0, то печать завершается
 inc ix
 push hl
 ld l,a
 ld h,0
 add hl,hl
 add hl,hl
 add hl,hl; каждый символ состоит из 8 байт, умножим код на 8
;ld de,#3C00
;add hl,de;3C00 - адрес, где хранятся символы
 ld a,h
 add a,#3C
 ld h,a
 ld de,hl;DE=адрес шрифта для символа
 pop hl;HL был нужен для вычисления адреса
 push hl; значение восстановлено
 ld a,8; начинается цикл 8 раз
m3: ld b,#80;Битовая маска для проверки данных в шрифте
 exa;  замена AF на AF', таким образом A запоминать не нужно
m2: ld a,(de)
 and b;тест байта шрифта
 jr z, writeatr;если результат=0, то занести в атрибуты пустое значение
 ld a,8; атрибут paper= синий(1)*8;если тест прошел, то запись в атрибуты будет проведена другим значением
writeatr:
 or 7; добавить к атрибутам белый INK=7
 ld (hl),a;запись цвета в атрибуты
 inc hl;следующий атрибут в памяти
 rrc b;сдвиг маски вправо #80->#40->...->#4->#2->#1
 jr nc, m2; сдвиг перенес данные во флаг переноса C, это и есть условие завершение цикла
 ld bc,24;первая линия нарисована 8 атрибутов
 add hl,bc; 24=32-8 переход к следующей линии
 inc de;следующий байт шрифта
 exa;AF'<->AF
 dec a
 jr nz,m3;цикл обработки от 8 до 0
 pop hl;прежний адрес атрибутов восстановлен
 ld bc,8
 add hl,bc; переход к следующему адресу на 8
 jp m1

;сами сообщения
message1: db "print Text 123456",0
message2: db "Moar messages",0
message3: db "TEXT",0

а теперь посчитаем такты команд пр расчете адреса шрифта:

  ld l,a;4
  ld h,0;7
  add hl,hl;11
  add hl,hl;11
  add hl,hl;11
  ld a,h;4
  add a,#3C;7
  ld h,a;4

выходит 59 тактов на символ,не считая того, что тратится на обработку данных при печати. Поэтому удобнее сформировать любой шрифт и расположить данные в памяти:

Font+256*0: первые байты шрифтов подряд
Font+256*1: вторые байты шрифтов подряд
...
Font+256*7: последние(седьмые по счету) байты шрифтов подряд

Процедура печати:

        ORG #8000
font_place equ #4800;адрес для наглядности шрифта, при использовании удобно поменять на #6000
font_place_hi equ font_place/256

begin
;-------формирование шрифта
 ld hl,#3c00
 ld de,font_place
m1:
 push de
 call myfont1;serzhfont;future;lordsfont;italic;bold;simple
 pop de
 inc e
 jr nz,m1

Печать текста

 ld hl,messaget
 ld de,#4021
 call printtext
stu: jr stu
messaget: db "Pretty text with font!",0

printtext
ptlp1: ld c,(hl)
 ld b,font_place_hi
 push de
 dup 8
 ld a,(bc)
 ld (de),a
 inc b
 inc d
 edup
 pop de
 inc de
 inc hl
 ld a,(hl)
 or a
 ret z
 jr ptlp1

формирование других шрифтов Для удобства команды внесены в директиву dupN..edup,например 8 означает 8 повторов команд.

simple
 dup 8
 ld a,(hl)
 ld(de),a
 inc hl
 inc d
edup
 ret


myfont1
 ld a,(hl)
 ld(de),a
 inc hl
 inc d

 ld a,(hl)
 rra
 or(hl)
 ld(de),a
 inc hl
 inc d

 dup 4
 ld a,(hl)
 ld(de),a
 inc hl
 inc d
edup
 ld a,(hl)
 rra
 or(hl)
 ld(de),a
 inc hl
 inc d

 ld a,(hl)
 ld(de),a
 inc hl
 inc d
 ret

serzhfont
 dup 4
 ld a,(hl)
 rra
 or(hl)
 ld(de),a
 inc hl
 inc d
 ld a,(hl)
 ld(de),a
 inc hl
 inc d
edup
 ret

future
 dup 4
 ld a,(hl)
 ld(de),a
 inc hl
 inc d
edup

 dup 4
 ld a,(hl)
 rra
 or (hl)
 ld(de),a
 inc hl
 inc d
edup
 ret

lordsfont
 dup 8
 ld a,(hl)
 ld c,a
 srl c
 srl c
 or c
 ld(de),a
 inc hl
 inc d
edup
 ret

bold
 dup 8
 ld a,(hl)
 rra
 or (hl)
 ld(de),a
 inc hl
 inc d
edup
 ret

italic
 dup 3
 ld a,(hl)
 rra
 ld(de),a
 inc hl
 inc d
edup

 dup 2
 ld a,(hl)
 ld(de),a
 inc hl
 inc d
edup

 dup 3
 ld a,(hl)
 rla
 ld(de),a
 inc hl
 inc d
edup
 ret