┌──────────────────────────────┐
│ │
│ ЭТЮДЫ │
│ │
└──────────────────────────────┘
Music by ZET and MITCHELL
(c) Колотов Сергей, г.Шадринск,
SerzhSoft, июль, 1997
РЕМЕЙК НЕКОТОРЫХ ПРОЦЕДУР
1993 ГОДА
В ZX-РЕВЮ-93 с.121 была опу-
бликована процедура Н.М.Стинова
под названием DOORS, реализую-
щая эффект очистки экрана путем
раздвигания изображения в сторо-
ны. Процедура занимает 101 байт
и, честно говоря, написана не
очень эффективно. Использованы
альтернативные регистры, но ре-
гистр HL так нигде и не сохра-
няется, что не дает возможности
вызывать эту процедуру из BA-
SIC'а. Применив команды блочной
пересылки LDIR и LDDR, удалось
"сдружить" новую процедуру с
бейсиком (благо в ней альтерна-
тивные регистры вообще не ис-
пользуются), более чем вдвое со-
кратить обьем занимаемой памяти
и значительно повысить быстро-
действие. Новая процедура также
стала полностью перемещаемой.
При очистке изображения на экра-
не устанавливаются текущие сис-
темные атрибуты из ячейки 23693.
То есть существует возможность
изменить цвета прямо из бейсика
командами INK, PAPER, BRIGHT,
FLASH или напрямую подав коман-
ду POKE 23693,n перед вызовом
процедуры по RANDOMIZE USR adr.
Выполнив POKE adr+1,n (n=1..16),
можно установить количество
сдвигов, выполняемых за один за-
пуск процедуры.
140.
; SCREEN-APART
3;(c) SerzhSoft, 11 july 1997
;
ORG 60000 ;адрес ассемблирования
;
ATTR_P EQU 23693 ;текущие атрибуты основного экрана
;
APART
LD B,#10 ;число пар сдвигов экрана в стороны
LP_APR1 PUSH BC ;сохраняем счетчик сдвигов на стеке
LD A,(ATTR_P) ;A=атрибуты для заполн. после сдига
LD DE,#5AFF ;самый последний байт атрибутов
LP_APR2 LD H,D ;скопировали этот адрес
LD L,E ; в HL и уменьшили на 1:
DEC HL ; адрес предпоследнего байта линии
LD BC,#000F ;сдвигать: 15 байт
LDDR ;сдвиг правой полу-линии вправо
LD (DE),A ;устанавливаем новое значение
LD BC,#FFF2 ;коррекция р-ра HL - теперь он
ADD HL,BC ; указывает на второй байт линии
LD E,L ;DE=HL
DEC E ;первый байт слева в линии
LD BC,#000F ;будем сдвигать 15 байт
LDIR ;сдвиг левой полу-линии влево
LD (DE),A ;устанавливаем новый байт (очистка)
LD BC,#FFEF ;коррекция регистра DE -
ADD HL,BC ; переход на одну
EX DE,HL ; линию вверх в экране (атрибутах)
BIT 3,D ;если атрибуты не кончились,
JR NZ,LP_APR2 ; то крутим цикл
XOR A ;перешли в область графики
BIT 6,D ;если мы пока еще не залезли в ПЗУ,
JR NZ,LP_APR2 ; то продолжаем крутить цикл
POP BC ;восстанавливаем счетчик сдвигов
DJNZ LP_APR1 ;крутим цикл положенное число раз
RET ;выход из процедуры
2
Шестнадцатеричный дамп проце-
дуры APART:
EA60: 06 10 C5 3A 8D 5C 11 FF :58
EA68: 5A 62 6B 2B 01 0F 00 ED :A1
EA70: B8 12 01 F2 FF 09 5D 1D :99
EA78: 01 0F 00 ED B0 12 01 EF :11
EA80: FF 09 EB CB 5A 20 E2 AF :33
EA88: CB 72 20 DD C1 10 D3 C9 :19
Сохранение: SAVE "aрart.c" CODE
60000,48
На стр.35 ZX-РЕВЮ-93 была
опубликована программа "теневой
контур". Мне удалось существен-
но улучшить эту процедуру, для
этого просто переписав ее "с ну-
ля". Новая процедура занимает
138 байт (старая - 211 байт) и
стала релоцируемой. Как и преж-
де, чтобы получить псевдо-трех-
мерное изображение, достаточно
выделить атрибутами с повышен-
ной яркостью те места на экране,
которым необходима тень, и выз-
вать процедуру SHADOW. Сущес-
твует возможность изменять кон-
фигурацию самой тени. Для этого
необходимо поменять значения в
двух командах загрузки регистро-
вой пары DE, которые помечены
звездочками. В представленной
программе установлены значения
#5500, #5500 соответственно, что
дает тень с немного закруглен-
ными краями. Подставив #2A80,
#AA80, получим тень с прямыми
краями. Чтобы получить тот же
результат, что и в оригинальном
варианте, необходимо установить
#AA00, #2A80. Ну а значения
#7F80, #FF80 покажут Вам сплош-
ную, нештрихованную тень.
140.
;SHADOW-PROCESSOR
3; (c) SerzhSoft, 11 july 1997
;
ORG 60000 ;адрес ассемблирования
SHADOW
LD HL,#5AFF ;последний байт атрибутов
LP_SHD1 LD BC,#0020 ;число байт в одной линии атрибутов
DEC HL ;переход к предыдущему атрибуту
BIT 3,H ;мы еще не "заехали" в графику?
RET Z ; если уже, то выход из процедуры
BIT 6,(HL) ;это атрибут с повышенной яркостью?
LP_SHD0 JR Z,LP_SHD1 ; если нет, то предыдущий атрибут
PUSH HL ;сохраняем адрес атрибута на стеке
INC L ;переход к следующему атрибуту
LD A,L ;проверка на переход
AND #1F ; к следующей линии атрибутов
JR Z,GO_SHD2 ;если да, то перепрыгиваем
BIT 6,(HL) ;включена ли яркость?
JR NZ,GO_SHD2 ; если да, то перепрыгиваем
PUSH HL ;сохраняем адрес атрибута на стеке
ADD HL,BC ;переход к атрибуту на линию ниже
LD C,(HL) ;поместили этот атрибут в регистр C
POP HL ;восстанавливаем адрес атрибута
LD A,H ;расчет адреса
AND #03 ; верхней линии
RLCA ; знакоместа
RLCA ; в экране
RLCA ; по заданному
OR #40 ; адресу в
LD H,A ; области атрибутов
LD DE,#5500 ;* образ для создания тени справа *
LD B,#0C ;высота тени: 12 пикселов
LP_SHD2 LD A,E ;сдвигаемый байт образа линии тени
AND #F0 ;отбрасываем лишние "правые" биты
OR (HL) ;накладываем содержимое экрана
LD (HL),A ;и записываем новый байт в экран
INC H ;----------------------------------
LD A,H ;
AND #07 ;стандартная
JR NZ,GO_SHD0 ; последовательность
LD A,L ; команд для перехода
ADD A,#20 ; на линию ниже
LD L,A ; в экранной области
JR C,GO_SHD1 ;
LD A,H ;
SUB #08 ;
LD H,A ;----------------------------------
GO_SHD1 LD A,H ;старший байт адреса в графике
CP #58 ;провер. на выход за границы экрана
JR NC,GO_SHD2 ;если да, то перепрыгиваем
BIT 6,C ;проверка яркости: можно ли изобра-
JR NZ,GO_SHD2 ; жать тень. если нет, то прыжок
GO_SHD0 SRL D ;вращение образа
RR E ; линии тени вправо
DJNZ LP_SHD2 ;цикл по числу линий в тени
GO_SHD2 POP HL ;восстанавливаем адрес атрибута
PUSH HL ;сохраняем адрес атрибута на стеке
LD BC,#0020 ;число байт в одной линии атрибутов
ADD HL,BC ;переход к атрибуту под текущим
LD A,H ;проверка нового адреса атрибута
CP #5B ; на вхождение в границы экрана
JR NC,GO_SHD4 ;если за пределами, то переход
BIT 6,(HL) ;если же входит в экран, но яркость
JR NZ,GO_SHD4 ; включена, то все равно - переход
INC L ;следующий байт атрибутов (правый)
LD C,(HL) ; помещаем в регистр C
LD A,H ;расчет адреса
AND #03 ; верхней линии
RLCA ; знакоместа
RLCA ; в экране
RLCA ; по заданному
OR #40 ; адресу в
LD H,A ; области атрибутов
LD DE,#5500 ;* образ для создания тени снизу *
LD B,#04 ;высота тени снизу
LP_SHD3 DEC L ;возврат на байт назад
LD A,(HL) ;взяли байт с экрана
OR D ;наложили левый байт образа линии
LD (HL),A ; тени и поместили назад в экран
INC L ;переход на байт вправо
LD A,L ;проверка на выход
AND #1F ; за правую границу экрана:
JR Z,GO_SHD3 ; если да, то перепрыгиваем
BIT 6,C ;если же атрибут с яркостью,
JR NZ,GO_SHD3 ; то так же - перепрыгиваем
LD A,(HL) ;взяли байт с экрана
OR E ;наложили правый байт образа линии
LD (HL),A ; тени и поместили назад в экран
GO_SHD3 INC H ;переход к следующей линии
SRL D ;вращение образа одной
RR E ; линии тени вправо
DJNZ LP_SHD3 ;цикл по числу линий в образе тени
GO_SHD4 POP HL ;восстанавливаем адрес атрибута
XOR A ;уст. флаг Z, чтобы JR Z сработала
JR LP_SHD0 ;переходим на команду JR Z,LP_SHD1
2
Шестнадцатеричный дамп проце-
дуры SHADOW:
EA60: 21 FF 5A 01 20 00 2B CB :DB
EA68: 5C C8 CB 76 28 F5 E5 2C :E5
EA70: 7D E6 1F 28 3A CB 76 20 :9F
EA78: 36 E5 09 4E E1 7C E6 03 :1A
EA80: 07 07 07 F6 40 67 11 00 :2D
EA88: 55 06 0C 7B E6 F0 B6 77 :57
EA90: 24 7C E6 07 20 13 7D C6 :7D
EA98: 20 6F 38 04 7C D6 08 67 :0E
EAA0: 7C FE 58 30 0A CB 71 20 :F2
EAA8: 06 CB 3A CB 1B 10 DC E1 :50
EAB0: E5 01 20 00 09 7C FE 5B :7E
EAB8: 30 2C CB 76 20 28 2C 4E :01
EAC0: 7C E6 03 07 07 07 F6 40 :5A
EAC8: 67 11 00 55 06 04 2D 7E :34
EAD0: B2 77 2C 7D E6 1F 28 07 :C0
EAD8: CB 71 20 03 7E B3 77 24 :ED
EAE0: CB 3A CB 1B 10 E8 E1 AF :3D
EAE8: 18 82 00 00 00 00 00 00 :6C
Сохранение: SAVE "shadow.c" CODE
60000,13
В ZX-РЕВЮ-93 на стр.117 была
напечатана процедура LOOK BASIC
PROGRAMMS, автор - Бессонов Але-
ксандр. Она занимает 344 байта,
что на мой взгляд - просто ко-
щунственно! Мне удалось сокра-
тить эту программу более чем
вдвое (точнее, переписать ее за-
ново). Принцип работы почти не
изменился, правда, появилась од-
на новая возможность. При печа-
ти обозначения какого-либо упра-
вляющего кода вслед за ним выво-
дится значение его параметра.
Например, после упр. кода 16
(INK CTRL) идет байт значения
цвета, что на экране будет выг-
лядеть примерно так: I[7] (все
инверсно). А после кодов 22 и 23
(AT CTRL, TAB CTRL) должно сле-
довать два значения: A[2][10]
или T[18][0]. В остальном прог-
рамма работает так же, как и
оригинал. Процедура занимает 158
байт.
140.
;
; LOOK BASIC PROGRAMS II
3; (c) SerzhSoft, 11 july 1997
;
ORG 65000 ;адрес ассемблирования
;
PROG EQU #5C53 ;сист. пер. "адрес начала BASIC-программы"
VARS EQU #5C4B ;сис. пер. "адрес начала BASIC-переменных"
;
OUT_NUM_2 EQU #1A28 ;сис. пр-ра "печать номера строки (HL)"
CHAN_OPEN EQU #1601 ;сис. пр-ра "открытие канала вывода"
STACK_NUM EQU #33B4 ;сис. пр-ра "поместить (HL) на стек к-ра"
STACK_A EQU #2D28 ;сис. пр-ра "поместить A на стек кальк-ра"
STACK_BC EQU #2D2B ;сис. пр-ра "поместить BC на стек к-ра"
PRINT_FP EQU #2DE3 ;сис. пр-ра "печать содержимого стека к."
;
LBP_2
LD A,#02 ;открываем канал вывода
CALL CHAN_OPEN ; на основной экран
LD HL,(PROG) ;адрес начала BASIC-программы
LP_LBP1 LD DE,(VARS) ;адрес начала BASIC-переменных
AND A ;сброс флага переноса для SBC
SBC HL,DE ;проверка на окончание программы
RET NC ;если HL>=DE, то выход из процедуры
ADD HL,DE ;восстанавливаем значение HL
PUSH HL ;сохраняем адрес строки на стеке
CALL OUT_NUM_2 ;печать номера строки
POP HL ;восстан-ем адрес строки со стека
PUSH HL ; и - опять же - сохраняем
LD B,H ;скопировали
LD C,L ; HL в BC
140. CALL PRN_BC ;распечатали адрес строки в памяти
POP HL ;восстан-ем адрес строки со стека
INC HL ;переход к
INC HL ; длине строки
LD C,(HL) ;младший байт длины строки
INC HL ;дальше
LD B,(HL) ;старший байт длины строки
INC HL ;переход к содержимому строки
PUSH HL ;сохраняем адрес на стеке
CALL PRN_BC ;печать длины текущей BASIC-строки
POP HL ;восстанавливаем адрес со стека
LP_LBP2 LD A,(HL) ;текущий символ строки
INC HL ;переход к следующему
CP #0D ;проверка на конец строки
JR Z,GO_LBP1 ;если да, то переход на обработку
LD DE,LP_LBP2 ;адрес цикла по символам кидаем на
PUSH DE ; стек, чтобы "вернуться" по RET
CP #0E ;наткнулись на число?
JR Z,GO_LBP2 ; если да, то переход на обработку
CP #08 ;код сдвига на одну позицию назад?
JR Z,GO_LBP3 ;если да, то обрабатываем
CP #10 ;если код символа меньше 16,
JR C,GO_LBP0 ; то печатаем его и -> к сл. симв.
CP #18 ;если 16 <= код символа <= 23,
JR C,GO_LBP4 ; то переход на обработку упр. кода
GO_LBP0 RST #10 ;печать одного символа
RET ;переход на LP_LBP2
;
GO_LBP1 RST #10 ;печать кода #0D - перевод строки
LD A,#0D ;и еще раз
RST #10 ; переводим строку
JR LP_LBP1 ;переход к следующей BASIC-строке
;
GO_LBP2 PUSH HL ;сохраняем адрес на стеке
CALL STACK_NUM ;5-байтное число -> на стек кальк.
CALL PRN_NUM ;печатаем его
POP HL ;восстанавливаем адрес со стека
LD BC,#0005 ;переход к символу BASIC-строки за
ADD HL,BC ; данным 5-байтным числом
RET ;переход на LP_LBP2
;
GO_LBP3 ADD A,#07 ;корректировка кода для #08
GO_LBP4 SUB #0F 3;получили число #00...#07 и занесли
LD C,A ; его в BC - это индекс (позиция)
LD B,#00 ; обозначения упр. кода в таблице
PUSH HL ;сохраняем адрес на стеке
LD HL,TBLCODE ;адрес таблицы обозначений упр. к.
ADD HL,BC ;адресовали элемент в этой таблице
SET 2,(IY+87) ;включить инверсию при печати
LD A,(HL) ;взяли обозн. упр. кода из таблицы
RST #10 ;напечатали его (обозначение)
RES 2,(IY+87) ;отключаем инверсию при печати
POP HL ;восстанавливаем адрес со стека
LD A,C ;определяем размер управл. кода:
OR A ;если это был код #08,
RET Z ;то выходим (у него нет параметров)
CP #06 ;если это были коды #16, #17, то
CALL NC,GO_LBP5 ; надо печатать два пераметра
GO_LBP5 LD A,(HL) ;взяли один байт из памяти (пар-р)
PUSH HL ;сохраняем адрес на стеке
CALL STACK_A ;забрасываем значение A на стек к.
CALL PRN_NUM ;печатаем это значение (параметр)
POP HL ;восстанавливаем адрес со стека
INC HL ;переход к след. символу в строке
RET ;"возврат" на GO_LBP5 или LP_LBP2
;
PRN_BC CALL STACK_BC ;помещаем BC на стек калькулятора
;
PRN_NUM SET 2,(IY+87) ;включить инверсию при печати
LD A,"[" ;распечатываем
RST #10 ; левую скобку (открывающую),
CALL PRINT_FP ; затем - число со стека кальк-ра,
LD A,"]" ; и, наконец печатаем
RST #10 ; правую скобку (закрывающую)
RES 2,(IY+87) ;отключаем инверсию при печати
RET ;возврат из подпрограммы
;
TBLCODE DB "<IPFBVAT" ;таблица обозначений управл. кодов
2
Шестнадцатеричный дамп проце-
дуры LBP_2:
FDE8: 3E 02 CD 01 16 2A 53 5C :E2
FDF0: ED 5B 4B 5C A7 ED 52 D0 :92
FDF8: 19 E5 CD 28 1A E1 E5 44 :0C
FE00: 4D CD 69 FE E1 23 23 4E :F4
FE08: 23 46 23 E5 CD 69 FE E1 :8C
FE10: 7E 23 FE 0D 28 16 11 10 :19
FE18: FE D5 FE 0E 28 14 FE 08 :37
FE20: 28 1D FE 10 38 04 FE 18 :C3
FE28: 38 17 D7 C9 D7 3E 0D D7 :0E
FE30: 18 BE E5 CD B4 33 CD 6C :D6
FE38: FE E1 01 05 00 09 C9 C6 :B3
FE40: 07 D6 0F 4F 06 00 E5 21 :85
FE48: 7E FE 09 FD CB 57 D6 7E :3E
FE50: D7 FD CB 57 96 E1 79 B7 :EB
FE58: C8 FE 06 D4 5E FE 7E E5 :B5
FE60: CD 28 2D CD 6C FE E1 23 :BB
FE68: C9 CD 2B 2D FD CB 57 D6 :49
FE70: 3E 5B D7 CD E3 2D 3E 5D :56
FE78: D7 FD CB 57 96 C9 3C 49 :50
FE80: 50 46 42 56 41 54 00 00 :41
Сохранение: SAVE "lbp_02.c" CODE
65000,15
* * *