(c) Бандура Сергей Иванович, 1996
Предлагаю процедуру, имитирующую поломку монитора. Процедура может
использоваться, например, вместо сообщения "Game Over" или в динамических
заставках. Тем, кому будет интересно попробовать свои силы в программировании,
мы предлагаем объединить программу, имитирующую телевизор (ZX-ревю 96/4-5 ,
стр. 7) и эту программу так, чтобы в итоге получились эффекты пропадания
сигнала, подаваемого на монитор, а потом его поломка. Далее будет идти
программа такого рода, но очистка экрана там производится по знакоместам.
10 ORG 40000
20 LD A,#3F
30 LD (23693),A
40 LD (23624),A
50 OUT (#FE),A
60 CALL #0D6B ; экран вспыхнул
70 HALT
80 LD A,#07
90 LD (23693),A
100 LD (23624),A
110 XOR A
120 OUT (#FE),A
130 CALL #0D6B ; экран погас
140 LD HL,20064
150 LD B,32
160 LD A,#FF
170 L0 LD (HL),A
180 INC H
190 LD (HL),A
200 DEC H
210 INC L
220 DJNZ L0 ; нет кадровой развертки (полоса
на середине экрана)
230 LD A,3
240 LD (23697),A
250 LD BC,#5000
260 LD HL,#80FF
270 L1 CALL PLOT
280 PUSH BC
290 INC B
300 CALL PLOT
310 LD C,L
320 CALL PLOT
330 DEC B
340 CALL PLOT
350 HALT
360 POP BC
370 INC C
380 DEC L
390 DEC H
400 JR NZ,L1 ; пропадает напряжение
410 LD A,3
420 LD (20079),A
430 LD (20335),A
440 XOR A
450 L2 LD (22895),A
460 CALL PAUSE
470 INC A
480 CP #08
490 JR NZ,L2 ; зажигается пятно
500 L3 CALL PAUSE
510 DEC A
520 LD (22895),A
530 JR NZ,L3 : гаснет пятно
540 RET
550 PAUSE PUSH AF
560 LD A,4
570 L00 HALT
580 DEC A
590 JR NZ,L00
600 POP AF
610 RET
620 PLOT PUSH HL
630 PUSH BC
640 CALL #22E5
650 POP BC
660 POP HL
670 RET
9C40: 3E 3F 32 8D 5C 32 48 5C :4A
9C48: D3 FE CD 6B 0D 76 3E 07 :B5
9C50: 32 8D 5C 32 48 5C AF D3 :5F
9C58: FE CD 6B 0D 21 60 4E 06 :0C
9C60: 20 3E FF 77 24 77 25 2C :BC
9C68: 10 F9 3E 03 32 91 5C 01 :6E
9C70: 00 50 21 FF 80 CD B3 9C :18
9C78: C5 04 CD B3 9C 4D CD B3 :C6
9C80: 9C 05 CD B3 9C 76 C1 0C :1C
9C88: 2D 25 20 E9 3E 03 32 6F :61
9C90: 4E 32 6F 4F AF 32 6F 59 :13
9C98: CD AA 9C 3C FE 08 20 F5 :9E
9CA0: CD AA 9C 3D 32 6F 59 20 :A6
9CA8: F7 C9 F5 3E 04 76 3D 20 :0E
9CB0: FC F1 C9 E5 C5 CD E5 22 :80
9CB8: C1 E1 C9 00 00 00 00 00 :BF
*************************************************************************
(c) А.Александров, г.Липецк.
Данная программа производит вычисление факториала. Особенность ее в том, что
предел вычислений неограничен, и производится индикация текущего множителя.
10 INPUT A : CLS
20 LET E=0 : LET B=1
30 FOR C=1 TO A : LET B=B*C
40 IF B<10 THEN GOTO 80
50 LET B=B/10 : LET E=E+1
60 IF B>10 THEN GOTO 50
70 PRINT AT 0,0;C
80 NEXT C
90 PRINT AT 0,0;A;"!=";B;"E+";E : GOTO 10
*************************************************************
(c) Юркиев Дмитрий, 1996
Предлагаю процедуру очистки экрана эффектом отключения телевизора. Как
уже говорилось выше, эта программа очищает экран по знакоместам, хотя лучше
было бы очистить его по линиям. Поэтому те, кому интересно могут
поэкспериментировать.
10 ORG 40000
20 LD B,5
30 CALL SNEG
40 LD HL,0
50 LD (VAR),HL
60 LD HL,22528
70 LD DE,23264
80 LD B,11
90 L0 PUSH BC
00 PUSH HL
110 PUSH DE
120 LD B,32
130 L1 LD (HL),0
140 XOR A
150 LD (DE),A
160 INC HL
170 INC DE
180 DJNZ L1
190 LD B,1
200 CALL SNEG
210 POP DE
220 POP HL
230 LD B,32
240 L2 DEC DE
250 DJNZ L2
260 LD BC,32
270 ADD HL,BC
280 POP BC
290 DJNZ L0
300 LD HL,22880
310 LD DE,22911
320 LD B,16
330 L4 PUSH BC
340 LD B,1
350 L3 PUSH BC
360 LD (HL),0
370 PUSH HL
380 LD BC,32
390 ADD HL,BC
400 LD (HL),0
410 POP HL
420 XOR A
430 LD (DE),A
440 PUSH DE
450 LD A,32
460 ADD A,E
470 LD E,A
480 XOR A
490 LD (DE),A
500 POP DE
510 POP BC
520 DJNZ L3
530 INC HL
540 DEC DE
550 LD B,1
560 CALL SNEG
570 POP BC
580 DJNZ L4
590 LD HL,16384
600 LD DE,16385
610 LD BC,6144
620 LD (HL),0
630 LDIR
640 RET
650 SNEG PUSH HL
660 PUSH DE
670 LD HL,(VAR)
680 L5 PUSH BC
690 PUSH HL
700 LD DE,16384
710 LD BC,6144
720 LDIR
730 POP HL
740 LD BC,20
750 ADD HL,BC
760 POP BC
770 DJNZ L5
780 LD (VAR),HL
790 POP DE
800 POP HL
810 RET
820 VAR DEFW 0
9C40: 06 05 CD AE 9C 21 00 00 :1F
9C48: 22 CB 9C 21 00 58 11 E0 :D7
9C50: 5A 06 0B C5 E5 D5 06 20 :FC
9C58: 36 00 AF 12 23 13 10 F8 :29
9C60: 06 01 CD AE 9C D1 E1 06 :D2
9C68: 20 1B 10 FD 01 20 00 09 :76
9C70: C1 10 E0 21 60 59 11 7F :27
9C78: 59 06 10 C5 06 01 C5 36 :4A
9C80: 00 E5 01 20 00 09 36 00 :61
9C88: E1 AF 12 D5 3E 20 83 5F :DB
9C90: AF 12 D1 C1 10 E8 23 1B :B5
9C98: 06 01 CD AE 9C C1 10 DB :FE
9CA0: 21 00 40 11 01 40 01 00 :F0
9CA8: 18 36 00 ED B0 C9 E5 D5 :B2
9CB0: 2A CB 9C C5 E5 11 00 40 :D8
9CB8: 01 00 18 ED B0 E1 01 14 :00
9CC0: 00 09 C1 10 EE 22 CB 9C :AD
9CC8: D1 E1 C9 00 00 00 00 00 :DF
*****************************************************************************
(c) Старков Павел, 1996
Прислал две процедуры, одна из которых производит очистку экрана
оригинальным способом, а другая вывод картинки на экран тем же способом. Для
второй процедуры необходимо загрузить картинку с адреса BUFF.
А теперь предлагаем листинг программы очистки экрана.
10 ORG 30000
20 CALL INIT
30 PRN1 LD DE,22527
40 LD HL,BUFF+6143+640
50 LD B,212
60 LOOP2 PUSH BC
70 PUSH HL
80 PUSH DE
90 LD BC,256+32
100 L2 PUSH BC
110 L3 PUSH HL
120 PUSH DE
130 PUSH BC
140 LD BC,32
150 LDDR
160 POP BC
170 POP DE
180 POP HL
190 CALL DWN_D
200 LD A,D
210 CP 88
220 POP IX
230 JR NC,EXT
240 PUSH IX
250 DJNZ L3
260 ADD HL,BC
270 POP BC
280 INC B
290 LD A,D
300 CP 88
310 JR C,L2
320 EXT POP DE
330 LD A,D
340 AND 7
350 JR NZ,PASS3
360 LD A,D
370 RRCA
380 RRCA
390 RRCA
400 AND 3
410 OR 88
420 PUSH DE
430 LD D,A
440 PUSH DE
450 POP HL
460 DEC DE
470 LD (HL),71
480 LD BC,31
490 LDDR
500 POP DE
510 PASS3 POP HL
520 CALL UP_D
530 LD A,D
540 CP 64
550 JR NC,L7
560 CALL DWN_D
570 L7 LD BC,32
580 AND A
590 SBC HL,BC
600 POP BC
610 LD A,B
620 CP 140
630 JR C,PASS1
640 HALT
650 PASS1 DJNZ LOOP2
660 RET
670 INIT XOR A
680 OUT (254),A
690 LD DE,BUFF+1
700 LD HL,BUFF
710 LD (HL),A
720 LD BC,639
730 LDIR
740 LD HL,16384
750 LD B,192
760 L1 PUSH HL
770 PUSH BC
780 LD BC,32
790 LDIR
800 POP BC
810 POP HL
820 CALL DWN_H
830 DJNZ L1
840 RET
850 DWN_H INC H
860 LD A,H
870 AND 7
880 RET NZ
890 LD A,L
900 ADD A,32
910 LD L,A
920 RET C
930 LD A,H
940 SUB 8
950 LD H,A
960 RET
970 DWN_D INC D
980 LD A,D
990 AND 7
1000 RET NZ
1010 LD A,E
1020 ADD A,32
1030 LD E,A
1040 RET C
1050 LD A,D
1060 SUB 8
1070 LD D,A
1080 RET
1090 UP_D DEC D
1100 LD A,D
1110 AND 7
1120 CP 7
1130 RET NZ
1140 LD A,E
1150 SUB 32
1160 LD E,A
1170 RET C
1180 LD A,D
1190 ADD A,8
1200 LD D,A
1210 RET
1220 BUFF DEFS 6784
7530: CD 9A 75 11 FF 57 21 6B :74
7538: 90 06 D4 C5 E5 D5 01 20 :B7
7540: 01 C5 E5 D5 C5 01 20 00 :1B
7548: ED B8 C1 D1 E1 CD CC 75 :E3
7550: 7A FE 58 DD E1 30 0C DD :6C
7558: E5 10 E7 09 C1 04 7A FE :EF
7560: 58 38 DE D1 7A E6 07 20 :9B
7568: 15 7A 0F 0F 0F E6 03 F6 :78
7570: 58 D5 57 D5 E1 1B 36 47 :B7
7578: 01 1F 00 ED B8 D1 E1 CD :31
7580: DB 75 7A FE 40 30 03 CD :FD
7588: CC 75 01 20 00 A7 ED 42 :35
7590: C1 78 FE 8C 38 01 76 10 :87
7598: A2 C9 AF D3 FE 11 ED 75 :6B
75A0: 21 EC 75 77 01 7F 02 ED :7D
75A8: B0 21 00 40 06 C0 E5 C5 :9E
75B0: 01 20 00 ED B0 C1 E1 CD :52
75B8: BD 75 10 F2 C9 24 7C E6 :B0
75C0: 07 C0 7D C6 20 6F D8 7C :22
75C8: D6 08 67 C9 14 7A E6 07 :C6
75D0: C0 7B C6 20 5F D8 7A D6 :ED
75D8: 08 57 C9 15 7A E6 07 FE :EF
75E0: 07 C0 7B D6 20 5F D8 7A :3E
75E8: C6 08 57 C9 00 00 00 00 :4B
А теперь программа вывода картинки на экран. Если сравнить эти программы,
то можно заметить, что они довольно схожи.
10 ORG 30000
20 CALL INIT
30 PRN1 LD DE,22527
40 LD HL,BUFF+6143+576+768
50 LD B,192+18
60 LOOP2 PUSH BC
70 PUSH DE
80 PUSH HL
90 LD A,B
100 LD BC,256+32
110 CP 193
120 JR NC,L2
130 LD A,D
140 CPL
150 AND 7
160 JR NZ,L2
170 LD A,D
180 RRCA
190 RRCA
200 RRCA
210 AND 3
220 PUSH DE
230 PUSH HL
240 PUSH BC
250 LD D,A
260 LD HL,BUFF
270 ADD HL,DE
280 OR 88
290 LD D,A
300 LD BC,32
310 LDDR
320 POP BC
330 POP HL
340 POP DE
350 L2 PUSH BC
360 L3 PUSH HL
370 PUSH DE
380 PUSH BC
390 LD BC,32
400 LDDR
410 POP BC
420 POP DE
430 POP HL
440 CALL UP_D
450 LD A,D
460 CP 64
470 POP IX
480 JR C,EXT
490 PUSH IX
500 DJNZ L3
510 AND A
520 SBC HL,BC
530 POP BC
540 INC B
550 LD A,D
560 CP 64
570 JR NC,L2
580 EXT POP HL
590 LD BC,32
600 AND A
610 SBC HL,BC
620 POP DE
630 POP BC
640 LD A,B
650 CP 193
660 JR NC,PASS3
670 CALL UP_D
680 LD A,B
690 PASS3 CP 65
700 JR NC,PASS1
710 HALT
720 PASS1 DJNZ LOOP2
730 RET
740 INIT XOR A
750 OUT (254),A
760 LD HL,22528
770 LD DE,22529
780 LD BC,767
790 LD (HL),A
800 LDIR
810 LD HL,BUFF
820 LD DE,16384
830 LD BC,6144
840 LDIR
850 LD DE,BUFF
860 LD BC,768
870 LDIR
880 LD HL,16384
890 LD B,192
900 L1 PUSH HL
910 PUSH BC
920 LD BC,32
930 LDIR
940 POP BC
950 POP HL
960 CALL DWN_H
970 DJNZ L1
980 PUSH DE
990 POP HL
1000 INC DE
1010 LD (HL),B
1020 LD BC,575
1030 LDIR
1040 LD HL,16384
1050 LD DE,16385
1060 LD (HL),B
1070 LD BC,6143
1080 LDIR
1090 INC DE
1100 INC HL
1110 LD BC,767
1120 LD (HL),71
1130 LDIR
1140 RET
1150 DWN_H INC H
1160 LD A,H
1170 AND 7
1180 RET NZ
1190 LD A,L
1200 ADD A,32
1210 LD L,A
1220 RET C
1230 LD A,H
1240 SUB 8
1250 LD H,A
1260 RET
1270 UP_D DEC D
1280 LD A,D
1290 AND 7
1300 CP 7
1310 RET NZ
1320 LD A,E
1330 SUB 32
1340 LD E,A
1350 RET C
1360 LD A,D
1370 ADD A,8
1380 LD D,A
1390 RET
1400 BUFF DEFS 7488
7530: CD A3 75 11 FF 57 21 56 :68
7538: 93 06 D2 C5 D5 E5 78 01 :10
7540: 20 01 FE C1 30 1F 7A 2F :8D
7548: E6 07 20 19 7A 0F 0F 0F :8A
7550: E6 03 D5 E5 C5 57 21 17 :BC
7558: 76 19 F6 58 57 01 20 00 :22
7560: ED B8 C1 E1 D1 C5 E5 D5 :6C
7568: C5 01 20 00 ED B8 C1 D1 :FA
7570: E1 CD 06 76 7A FE 40 DD :A4
7578: E1 38 0E DD E5 10 E7 A7 :74
7580: ED 42 C1 04 7A FE 40 30 :D1
7588: DC E1 01 20 00 A7 ED 42 :B1
7590: D1 C1 78 FE C1 30 04 CD :CF
7598: 06 76 78 FE 41 30 01 76 :E7
75A0: 10 99 C9 AF D3 FE 21 00 :28
75A8: 58 11 01 58 01 FF 02 77 :58
75B0: ED B0 21 17 76 11 00 40 :C1
75B8: 01 00 18 ED B0 11 17 76 :81
75C0: 01 00 03 ED B0 21 00 40 :37
75C8: 06 C0 E5 C5 01 20 00 ED :BB
75D0: B0 C1 E1 CD F7 75 10 F2 :D2
75D8: D5 E1 13 70 01 3F 02 ED :B5
75E0: B0 21 00 40 11 01 40 70 :28
75E8: 01 FF 17 ED B0 13 23 01 :48
75F0: FF 02 36 47 ED B0 C9 24 :6D
75F8: 7C E6 07 C0 7D C6 20 6F :68
7600: D8 7C D6 08 67 C9 15 7A :67
7608: E6 07 FE 07 C0 7B D6 20 :A1
7610: 5F D8 7A C6 08 57 C9 00 :25
*******************************************************************************
(c) Андрияшкин Александр, 1996
Александр предлагает погамму печати текста:
1. Кусок программы:
INC HL [6 тактов]
DEC BC [6 тактов]
LD A,B [4 такта]
OR C [4 такта]
JR NZ,LOOP [7/12 тактов]
Можно заменить на аналогичный:
CPI [16 тактов]
JP PE,LOOP [10 тактов]
Он короче на 1 байт и работает быстрее.
2. В следующей конструкции содержимое аккумулятора будет уменьшаться до
тех пор, пока станет равно MIN, дальнейшего уменьшения не последует.
CP MIN+1
CCF
SBC A,0
И, в итоге, он приводит программу печати текста в окне путем скроллинга
этого окна снизу вверх на один пиксел. Отличие ее в том, что она не требует
специального буфера.
10 ORG 40000
20 START LD HL,TXT
30 PUSH HL
40 M1 LD C,8
50 M2 LD B,20 ; ширина окна в знакоместах
60 PUSH BC
70 LD B,#63 ; высота окна в пикселах
80 LD HL,#4806 ; адрес левого верхнего угла
90 M3 PUSH BC
100 LD D,H
110 LD E,L
120 INC H
130 LD A,H
140 AND 7
150 JR NZ,$+12
160 LD A,L
170 SUB #E0
180 LD L,A
190 JR NC,$+6
200 LD A,H
210 SUB 8
220 LD H,A
230 LD BC,20 ; ширина окна в знакоместах
240 PUSH HL
250 LDIR
260 POP HL
270 POP BC
280 DJNZ M3
290 EX DE,HL
300 POP BC
310 POP HL
320 PUSH HL
330 M4 PUSH HL
340 PUSH DE
350 LD A,(HL)
360 INC A
370 ADD A,A
380 LD H,0
390 LD L,A
400 ADD HL,HL
410 ADD HL,HL
420 LD DE,FONT-256
430 ADD HL,DE
440 LD A,L
450 SUB C
460 JR NC,$+3
470 DEC H
480 LD L,A
490 LD A,(HL)
500 POP DE
510 LD (DE),A
520 POP HL
530 INC HL
540 INC DE
550 DJNZ M4
560 LD B,4 ; скорость перемещения
570 M6 HALT
580 LD A,#BF
590 IN A,(#FE)
600 RRCA
610 JR NC,EXIT
620 DJNZ M6
630 DEC C
640 JR NZ,M2
650 LD A,(HL)
660 OR A
670 EX (SP),HL
680 JR NZ,M1
690 EXIT POP HL
700 RET
710 TXT DEFM " "
720 DEFM " Written by "
730 DEFM " Andrijashkin "
740 DEFM " @ 1996 "
750 DEFM " "
760 DEFB 0
770 FONT EQU 15616
Чтобы процедура работала хорошо, надо, чтобы длина текста была кратна
ширине окна (в данном случае 20), и после этого был байт 0.
9C40: 21 A1 9C E5 0E 08 06 14 :4F
9C48: C5 06 63 21 06 48 C5 54 :9A
9C50: 5D 24 7C E6 07 20 0A 7D :7D
9C58: D6 E0 6F 30 04 7C D6 08 :A7
9C60: 67 01 14 00 E5 ED B0 E1 :DB
9C68: C1 10 E3 EB C1 E1 E5 E5 :0F
9C70: D5 7E 3C 87 26 00 6F 29 :E0
9C78: 29 11 00 3C 19 7D 91 30 :E1
9C80: 01 25 6F 7E D1 12 E1 23 :16
9C88: 13 10 E4 06 04 76 3E BF :A8
9C90: DB FE 0F 30 0A 10 F6 0D :61
9C98: 20 AC 7E B7 E3 20 A5 E1 :BE
9CA0: C9 20 20 20 20 20 20 20 :E5
9CA8: 20 20 20 20 20 20 20 20 :44
9CB0: 20 20 20 20 20 20 20 20 :4C
9CB8: 20 20 57 72 69 74 74 65 :13
9CC0: 6E 20 62 79 20 20 20 20 :45
9CC8: 20 20 20 20 20 41 6E 64 :17
9CD0: 72 69 6A 61 73 68 6B 69 :C1
9CD8: 6E 20 20 20 20 20 20 20 :C2
9CE0: 20 20 20 20 40 20 31 39 :C6
9CE8: 39 36 20 20 20 20 20 20 :B3
9CF0: 20 20 20 20 20 20 20 20 :8C
9CF8: 20 20 20 20 20 20 20 20 :94
9D00: 20 20 20 20 20 00 00 00 :3D
Также, Александр предлагает использовать в процедурах печати при расчете
адреса шаблона буквы, заменить первый ADD HL,HL на ADD A,A. При этом экономится
11-4=7 тактов. Но при этом не будут использоваться символы с кодом больше 127.
То же можно сделать и со второй командой ADD HL,HL, сократив число символов до
64.
Если в программе строки с 70 по 280 выделить в подпрограмму и вызывать ее
два раза, то можно получить скроллинг букв двойной высоты.
*********************************************
(C)1996 Колотов Сергей, Шадринск
В ZX-РЕБЮ 96/4-5, читая раздел "Этюды", я наткнулся на процедуры опроса
клавиш. Принцип, использованный А. Шокало совсем неплох, но сами программы
вызвали у меня внутренний протест. "Слишком много лишних байтов!" - подумал я и
сел за компьютер.
Вскоре новые процедурки уже были написаны и отлажены. Принцип работы остался
прежним, а вот размер значительно уменьшился. Итак, "свежие" процедуры:
Listing 1. Клавиатурные процедурки.
REDEF ;ждет нажатия на любую клавишу
;на выходе:
; B=старший байт порта клавиатуры
; A=маска нажатой клавиши (бит установлен в 1)
LD BC,#FEFE ;адрес порта опроса клавиатуры
LP_DEF RRC B ;"пробегаем" все полуряды
IN A,(C) ;считываем данные из порта
CPL ;инвертируем все биты
AND #1F ;отбрасываем 3 ненужных бита
JR Z,LP_DEF ;если нет нажатий, то продолжить
RET ;возврат из процедуры
;
TRANSF ;декодирует данные REDEF в код символа
;на входе:
; B=старший байт порта клавиатуры
; A=маска нажатой клавиши (бит установлен в 1)
;на выходе:
; A=код клавиши (C.S.=#E3, S.S.=#0E, ENTER=#0D)
LD H,B ;H=порт клавиатуры
LD B,#04 ;определяем
LPTR1 RRA ; порядковый
JR C,GOTR1 ; номер
DJNZ LPTR1 ; клавиши
GOTR1 LD A,B ; в полуряде
ADD A,A ;умножаем
ADD A,A ; его
ADD A,A ; на 8
LD B,#07 ;определяем
LPTR2 RR H ; порядковый
JR NC,GOTR2; номер
DJNZ LPTR2 ; полуряда
GOTR2 ADD A,B ;прибавляем K аккумулятору
ADD A,#05 ;смещение
LD L,A ; в таблице
LD H,#02 ;адрес таблицы в пзу: #0205
LD A,(HL) ;A=код клавиши из таблицы
RET ;выход из процедуры
Метка REDEF. Ожидается нажатие любой клавиши (кроме RESET, естественно), и
результат работы помещается в регистры A и В (как не вспомнить: "сидели на
трубе!"). Регистр B содержит старший байт адреса порта клавиатуры (полуряд),
а в аккумуляторе находится маска нажатой клавиши (соответствующий бит включен).
Длина процедуры 13 байт.
Метка TRANSF - перекодировка в код символа. Результаты предыдущей процедуры
перерабатываются и, в соответствии с таблицей
из ПЗУ (адрес таблицы #0205), код символа помещается в аккумулятор. То есть
A=(#30..#39, #41..#5A) - цифры и прописные английские буквы. Следует также
отметить, что несимвольным клавишам присвоены следующие коды: SPACE - #20,
CAPS SHIFT - #E3, SYMBOL SHIFT - #0E, ENTER - #0D. Длина процедуры 28 байт.
В ZX-РЕВЮ 96/3 на стр. 51 опубликована статья Владимира Зореева с
доработанной им процедурой печати спрайта Вадима Бодрова (ZX-РЕВЮ 95/4, стр. 15).
Да, я согласен, что скорость увеличилась, но можно еще быстрее. А насчет
"оригинального алгоритма, придуманного мной" - как пишет Владимир, так даже и
не знаю, что сказать...
Абсолютно такие же алгоритмы можно найти практически в любой игре или
программе, использующей спрайтовую (растровую) графику. Примеры же программ,
основанных на данном методе, можно встретить и в широко распространенных
изданиях "Инфоркома". Например, ZX FORUM'94 - там стрелка выводится именно
таким способом. Или все то же ZX РЕВЮ 95/5 - в статье на стр. 29 процедура
печати 42 символов в строке использует ту же технику. Похоже, вновь "изобретен
велосипед".
Перейдем от грустного к более приятному - к новой процедуре, работающей
быстрее предыдущей. Спрайты, смещение которых относительно байта равно 0
печатаются вообще отдельной подпрограммкой и появляются на экране практически
мгновенно. Объем расходуемой памяти немного увеличился, но на притягательность
любой графической программы влияет прежде всего скорость вывода на экран, так
что это не так уж и страшно. Вдобавок, процедуру можно вызывать как из бейсика,
так и из машинных кодов, что более актуально. Длина процедуры 220 байт.
Listing 2. Быстрый вывод спрайта
; SPRITE OUTPUT 2.3
; (C)SERZHSOFT'1996
;DEF FN M(X,Y,L,H,A,O)=USR 65005
;
ORG 65005 ;адрес ассемблирования
;
DEF_FN ;точка входа из бейсика по DEF FN
LD IX,(#5C0B) ;IX=адрес параметров DEF FN
LD D,(IX+4) ;X-координата спрайта
LD E,(IX+12) ;Y-координата спрайта
LD B,(IX+20) ;ширина спрайта в байтах
LD C,(IX+28) ;высота спрайта в пикселях
LD L,(IX+36) ;адрес спрайта
LD H,(IX+37) ; в памяти
LD A,(IX+44) ;режим вывода на экран
;
PUTSPR ;точка входа из маш. кодов
;D: X-координата, е: Y-координата
;B: ширина, C: высота
;HL: адрес спрайта
;A: режим вывода (0=OR, 1=XOR, 2=AND)
EX AF,AF' ;альтернативный аккумулятор
XOR A ; обнуляется -
EX AF,AF' ; это будет маска для сдвига
CP 1 ;проверка:
LD A,180 ; если A<1 (т.е. A=0), то
JR C,GOPS1 ; A=180 (OR H) и переход
LD A,172 ;если A=1, то
JR Z,GOPS1 ; A=172 (XOR H) и переход
LD A,164 ;если A>1, то A=164 (AND H)
EX AF,AF' ;раз AND, значит необходимо
CPL ; AF'=255, что и
EX AF,AF' ; выполняем (A=0, CPL => A=255)
GOPS1 LD (MODE_1),A ;исправляем
INC A ; необходимые
LD (MODE_2),A ; команды вывода
INC A ; в зависимости
LD (MODE_5),A ; от режима (OR, XOR, AND)
EX AF,AF' ;A=маска сдвига
LD (MODE_0+1),A ;поместили "куда надо"
AND D ;операция "и" с X-коорд.
AND #07 ;теперь A=0..7: смещение
LD (MODE_4+2),A ; в таблице TBL_OR
LD A,D ;координата X
AND #07 ;позиция первого бита в байте экрана
EX AF,AF' ;запомнили в AF'
PUSH HL ;пихнули адрес спрайта на стек
LD A,#BF ;максимальная Y-координата
SUB E ;отсчет координат
LD E,A ; снизу-вверх
LD A,E ;------------------------
RRA ; расчет адреса в экране
SCF ; по координатам:
RRA ;
RRA ;на входе:
AND #5F ; D=X-координата
LD H,A ; E=Y-координата
XOR D ;
AND #07 ;на выходе:
XOR D ; HL=адрес в экране
RRCA ;
RRCA ;D,E не меняются
RRCA ;
LD L,A ;используется
LD A,E ; аккумулятор
XOR H ;
AND #07 ;
XOR H ;
LD H,A ;------------------------
EX AF,AF' ;вспомнили позицию бита
JR Z,NOSHFT ;если =0, то переход
LD (JUMPER+1),A ;поместили в JR для прыжка
LD IX,TBL_OR ;IX=адрес таблицы TBL_OR
MODE_4 LD A,(IX+0) ;байт со смещением 0..7 из
LD (MODE_3+1),A ; таблицы (для OR)
POP IX ;IX=адрес начала спрайта
EX DE,HL ;DE=адрес байта в экране
LPPS1 PUSH BC ;сохранили ширину и высоту
LD A,E ;сохранили регистр E
EX AF,AF' ; в AF'
LPPS2 LD L,(IX+0);L=байт спрайта
MODE_0 LD H,#00 ;H=0 для OR, XOR; H=255 для AND
JUMPER JR $ ;прыжок через лишние ADD HL,HL'ы
ADD HL,HL ;-------------
ADD HL,HL ;
ADD HL,HL ;сдвиг байта
ADD HL,HL ; спрайта
ADD HL,HL ; нужное
ADD HL,HL ; число раз
ADD HL,HL ;
ADD HL,HL ;-------------
LD A,(DE) ;взяли байт с экрана
MODE_1 OR H ;OR, XOR или AND
LD (DE),A ;поставили назад
INC E ;следующий байт экрана
LD A,L ;дополнили регистр L нужными
MODE_3 OR #00 ; включенными битами (как-будто
LD L,A ; не ADD HL,HL'ы, A RLC HL'ы)
LD A,(DE) ;байт с экрана
MODE_2 OR L ;OR,XOR или AND
LD (DE),A ;поместили обратно
INC IX ;следующий байт спрайта
DJNZ LPPS2 ;повторять "ширина" раз
EX AF,AF' ;восстановили
LD E,A ; регистр E
INC D ;следующая линия экрана
LD A,D ;если мл. 3 бита регистра D
AND #07 ; равны нулю, то
JR Z,GOPS3 ; переход на корректировку
GOPS2 POP BC ;восстановили ширину и высоту
DEC C ;повторять цикл
JP NZ,LPPS1; "высота" раз
RET ;выход из процедуры
GOPS3 LD A,E ;--------------------
ADD A,#20 ;
LD E,A ;корректировка DE
JR C,GOPS2 ; для перехода на
LD A,D ; линию ниже
SUB #08 ; (в экране)
LD D,A ;
JP GOPS2 ;--------------------
;
NOSHFT ;вывод спрайта по байтам (X-координата кратна 8)
POP DE ;DE=адрес спрайта в памяти
LPPS3 PUSH BC ;сохранили ширину и высоту
LD A,L ;запомнили
EX AF,AF' ; регистр L в AF'
LPPS4 LD A,(DE) ;взяли байт спрайта
MODE_5 OR (HL) ;OR, XOR или AND
LD (HL),A ;поместили на экран
INC DE ;следующий байт спрайта
INC L ;следующий байт экрана
DJNZ LPPS4 ;цикл "ширина" раз
EX AF,AF' ;восстановили
LD L,A ; регистр L
INC H ;перешли к следующей линии экрана
LD A,H ;если младшие 3 бита регистра H
AND #07 ; равны нулю, то
JR Z,GOPS5 ; перейти на корректировку
GOPS4 POP BC ;вспомнили ширину и высоту
DEC C ;повторили
JP NZ,LPPS3; "высота" раз
RET ;выход из процедуры
GOPS5 LD A,L ;-------------------
ADD A,#20 ;
LD L,A ;корректировка HL
JR C,GOPS4 ; для перехода
LD A,H ; на линию ниже
SUB #08 ; (в экране)
LD H,A ;
JP GOPS4 ;-------------------
;
;таблица для наложения на байты после их сдвига
;(для имитации команд "RLC HL" через ADD HL,HL)
TBL_OR DB #00,#7F,#3F,#1F,#0F,#07,#03,#01
;
;END OF SPRITE OUTPUT 2.3
Listing 3. Дамп процедуры SPRITE OUTPUT
FDED: DD 2A 0B 5C DD 56 04 DD :6C
FDF5: 5E 0C DD 46 14 DD 4E 1C :DA
FDFD: DD 6E 24 DD 66 25 DD 7E :2C
FE05: 2C 08 AF 08 FE 01 3E B4 :DF
FE0D: 38 09 3E AC 28 05 3E A4 :45
FE15: 08 2F 08 32 72 FE 3C 32 :62
FE1D: 7A FE 3C 32 A0 FE 08 32 :D9
FE25: 66 FE A2 E6 07 32 58 FE :9E
FE2D: 7A E6 07 08 E5 3E BF 93 :0F
FE35: 5F 7B 1F 37 1F 1F E6 5F :E6
FE3D: 67 AA E6 07 AA 0F 0F 0F :10
FE45: 6F 7B AC E6 07 AC 67 08 :E1
FE4D: 28 4C 32 68 FE DD 21 C1 :16
FE55: FE DD 7E 00 32 77 FE DD :30
FE5D: E1 EB C5 7B 08 DD 6E 00 :BA
FE65: 26 00 18 FE 29 29 29 29 :43
FE6D: 29 29 29 29 1A B4 12 1C :0B
FE75: 7D F6 00 6F 1A B5 12 DD :13
FE7D: 23 10 E2 08 5F 14 7A E6 :6B
FE85: 07 28 06 C1 0D C2 5F FE :A5
FE8D: C9 7B C6 20 5F 38 F4 7A :BA
FE95: D6 08 57 C3 88 FE D1 C5 :A7
FE9D: 7D 08 1A B6 77 13 2C 10 :B6
FEA5: F9 08 6F 24 7C E6 07 28 :C8
FEAD: 06 C1 0D C2 9C FE C9 7D :21
FEB5: C6 20 6F 38 F4 7C D6 08 :8E
FEBD: 67 C3 AE FE 00 7F 3F 1F :6E
FEC5: 0F 07 03 01 FD FD FD FD :D1
Работая на ассемблере уже несколько лет, я долгое время так и не знал
принципа работы (стыдобушка!) команды DAA (#27). Но вот недавно, загрузив
непревзойденный STS, я наконец детально разобрался в алгоритме работы этой
операции, чем и делюсь с теми, кто по каким-то причинам до сих пор этого не
сделал.
На работу команды влияют флаги C,H,N, а также содержимое регистра A.
Алгоритм:
1. Если флаг N выключен (равен 0), то в последующих шагах выполняется операция
сложения. Если же включен (равен 1), то операция вычитания.
2. Если аккумулятор больше #90 или флаг C включен, то к аккумулятору
прибавляется (вычитается) #60. Здесь не случайно написано "или". Если и
A>#90, и CF=1, то сложение (вычитание) #60 происходит всего лишь один раз.
3. Если младший полубайт больше #9 или флаг H включен, то аналогично п.2 к
аккумулятору прибавляется (вычитается) #06. Здесь также работает принцип
OR.
И еще, в копилку эффективных приемов программирования...
Как-то раз, программируя на ассемблере, я столкнулся с одной проблемой. Шла
интенсивная работа с экраном и использовалось большое количество мелких
вложенных циклов. Регистров катастрофически не хватало, а использовать стек не
представлялось возможным - он был переустановлен на данные.
Но выход я все-таки нашел.
Было решено, что один регистр будет отвечать сразу за несколько переменных
циклов. Вот как это, примерно, выглядело:
...
LD A,%00000101
;биты: xxxyyzzz
LP1 OR %00010000
LP2 OR %10000000
LP3 EX AF,AF'
...
EX AF,AF'
SUB %00100000
JR NC,LP3
AND %00011111
SUB %00001000
JR NC,LP2
AND %00000111
SUB %00000001
JR NC,LP1
...
Говоря нормальным языком, под переменные каждого цикла отводилось по
нескольку бит регистра A. В вышеприведенном примере аккумулятор разбивался на
три части: биты 0,1,2; 3,4; 5,6,7. А число циклов было соответственно 6, 3, 5.
Чем больше порядковый номер битов, тем вложенней цикл. Значения, задаваеммые
командами LD A,...; OR ... должны быть на единицу меньше числа выполняемых
циклов. В самом внешнем цикле вместо SUB ... можно написать DEC A с последующей
проверкой флага Z. Но в этом случае в команде LD A,... необходимо задавать
реальное число циклов, а не уменьшенное на 1. Командами AND ... сбрасываются