§ Теория
Безусловно, любая программа должна информировать пользователя о том, что она делает. Ну почти любая, конечно, но все же, большинство из них. Первым делом, надо бы научиться выводить символы и строки на экран. Сегодня я попытаюсь рассказать об этом.Как известно, в спектруме нет текстового режима, есть лишь только графический, и потому, чтобы вывести что-то на экран, это придется нарисовать разными методами. Рассмотрю лишь самый простой, который работает с символами размером 8x8 и полем 32x24.
Первое, что требуется, так это информация о записанных символах где-нибудь в памяти. Если 1 символ кодируется 8 байтами, а как известно, 1 байт равен 8 пикселям, то для хранения 256 символов потребуется 2048 байт (2кб) памяти. А памяти в спектруме не так много, к тому же, я буду полностью опускать все символы, имеющие код от 128 до 255 - это обычно там находится русская кодировка. Плюс к этому, еще буду пропускать символы от 0 до 31 - там находятся спецсимволы. Все ради экономии места. Итак, в распоряжении остаются символы от 32 до 127 включительно, а это 96 символов, которые займут в памяти 768 байт - уже много меньше, чем 2кб, хотя можно и еще ужать до 384 байта, если использовать символы 4x8, но пока я это делать тут не буду, может потом сделаю в другой главе.
Поскольку размер ROM состоит из 16кб, то логично бы хранить таблицу символов в последних 768 байтах, как это делается в ROM Бейсике от официального Синклера, так сказать. А они там находятся по адресу 0x3D00 до 0x3FFF включительно.
§ Вычисление адреса данных для показа
Как вычислить позицию данных, откуда будем считывать символы? Просто, очень просто:1word get_symbol_address(byte sym) { 2 return 0x3D00 | ((sym - 0x20) << 8); 3}На языке ассемблера Z80 это будет выглядеть так. Все просто:
1; Вход: A (символ) 2; Выход: HL 3get_symbol_address: 4 5 sub 0x20 ; A = Sym - 0x20 6 ld h, 0 ; HL = A 7 ld l, a 8 add hl, hl 9 add hl, hl 10 add hl, hl ; HL = A << 3 11 ld a, h 12 add 0x3d 13 ld h, a ; HL += 0x3D00 14 ret
§ Вывод символа на экран
Для вывода одного символа на экран нам потребуется использовать 2 процедуры, которые ранее написаны - это вычисление источника символа, и вычисление адреса, куда писать будем. Ну а дальше просто дело техники.1; Вход: B(y=0..23), C(x=0..31) A(символ) 2print_char: 3 4 push bc 5 push de 6 push hl 7 call get_symbol_address ; HL=Адрес символа в памяти 8 ex de, hl ; DE теперь тут 9 call get_text_cursor_address ; HL=Адрес видеопамяти 10 ld b, 8 ; Повторить 8 раз 11.pc1: ld a, (de) ; Прочитать 8 бит 12 ld (hl), a ; Записать 8 бит 13 inc h ; Y = Y + 1 согласно модели памяти 14 inc de ; К следующему байту 15 djnz .pc1 ; Рисовать 8 строк 16 pop hl 17 pop de 18 pop bc 19 ret
§ Процедура очистки экрана
Я подумал, что не лишним будет привести сюда процедуру, которая очищает экран в атрибут A, в том числе еще и устанавливая BORDER под цвет БУМАГИ.1; Вход: A - атрибут очистки 2cls: 3 ld bc, 0x02FF 4 ld hl, 0x5800 ; Отсюда копировать 5 ld de, 0x5801 ; Сюда 6 ld (hl), a ; Байт инициализации 7 rrca 8 rrca 9 rrca 10 out (254), a ; Цвет бордера 11 ldir ; Копировать из (HL) -> (DE), HL++, DE++ 12 xor a 13 ld hl, 0x4000 14 ld (hl), a 15 ld de, 0x4001 16 ld bc, 0x17FF 17 ldir ; Очистить графическую область 18 ret