ZX-Ревю 1996 №7-8 1995 г.

Этюды - процедура имитирующая поломку монитора.


(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 ... сбрасываются




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Система - Этот раздел нашего журнала посвещается очень наболевшей у могих проблеме, как работать со множеством утилитсистемы и использовать их в bat файлах, как настроить систему is-dos.
Гвоздь - подробное описание стратегической игры The Dark Empire.
Открытые письма Nemo №4.8
Вступление - Зa oкнoм нoчь. Нa стoле стoит SPECCY...
Анкета - Вreeze/Fishbone.

В этот день...   23 апреля