┌──────────────────────────────┐ │ │ │ ЭТЮДЫ │ │ │ └──────────────────────────────┘ 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 * * *