push hl,de,bc,af
Написать сей опус меня толкнули работа с демо, где пришлось использовать трюки работы со стеком, а так же некоторые запросы, которые были услышаны в чатах и на форумах.
Пожалуй, я рисну рассмотреть просты примеры.
Начну с простой задачи: как очистить экран? Начинающий Спектрумист скажет: "Легко!" и напишет примерный код:
ld hl,$4000;начальный адрес
ld de,$4001
ld bc,6143;размер экрана
ld (hl),0
ldir
Здесь написано верно, но теперь понадобятся простые подсчеты:
инструкция z80 ldir занимает 21/16 тактов на байт, выходит 21*6143=129003 тактов, а это очень много. При постоянной анимации такой подход не пройдет.
Вернуь к статье в забытом журнале ZX ревю:
инструкция push r16,(r16 - hl,de,bc) выполняется 11 тактов, причем push заполнит два байта. получается 6144/2*11=33792 тактов. Ого, уже лучше.
Возникает вопрос: а как применить?
Да очень просто, вот исходный тект ассемблера sjsmplus (stack_cls.asm):
ld hl,0
lp:
ei
halt
ld (back_sp+1),sp;запомнить значение стека
ld sp,$5800;новый указатель памяти на конец экранной
памяти
dup 3072;развернутый цмкл
push hl
edup
back_sp:ld sp,0
jr $
Теперь я внезу небольшие изменения в код:
device zxspectrum128
ORG #6000
begin
ld hl,0
lp:
ei
halt
ld (back_sp+1),sp;запомнить значение стека
ld sp,$5800;новый указатель памяти на конец экранной
памяти
dup 3072;развернутый цмкл
push hl
edup
back_sp:ld sp,0
inc hl
jp lp
jr $
end
display /d,end-begin
savesna "!stack_cls.sna",begin
Все выглядит четко, но на экране картинка немного искажается. В чем причина?
Следует описать процесс рисования:
device zxspectrum128
ORG #6000
begin
lp:
ei
halt
ld (back_sp+1),sp;запомнить значение стека
ld sp,pat
ld a,0:out ($FE),a;рамка черная
pop hl,de,bc,af
exx
exa
pop hl,de,bc,af
exx
exa
ld sp,$5000;новый указатель памяти на конец экранной
памяти
; dup 8
dup 128
push hl
edup
dup 128
push de
edup
dup 128
push bc
edup
dup 128
push af
edup
exx
exa
dup 128
push hl
edup
dup 128
push de
edup
dup 128
push bc
edup
dup 128
push af
edup
exx
exa
;edup
back_sp:ld sp,0
ld a,7:out ($FE),a;рамка белая - так по старинке
выполняется измерение времени исполнения программы
jp lp
pat:
db %01111100,%01111100
db %10000010,%10000010
db %10111010,%10111010
db %10000010,%10000010
db %10101010,%10101010
db %10000010,%10000010
db %01111100,%01111100
db %00000000,%00000000
end
display /d,end-begin
savesna "!stack_pat.sna",begin
device zxspectrum128
ORG #6000
begin
;full screen
lp:
ei
halt
ld a,0:out ($FE),a
ld hl,$4800:call draw
ld a,1:out ($FE),a
ld hl,$5000:call draw
ld a,2:out ($FE),a
ld hl,$5800:call draw
ld a,3:out ($FE),a
jp lp
draw:
ld (back_sp+1),sp;запомнить значение стека
ld (sp1+1),hl
ld sp,pat
pop hl,de,bc,af
exx
exa
pop hl,de,bc,af
exx
exa
sp1: ld sp,$5000
; dup 8
dup 128
push hl
edup
dup 128
push de
edup
dup 128
push bc
edup
dup 128
push af
edup
exx
exa
dup 128
push hl
edup
dup 128
push de
edup
dup 128
push bc
edup
dup 128
push af
edup
exx
exa
;edup
back_sp:ld sp,0
ret
pat:
db %01111100,%01111100
db %10000010,%10000010
db %10111010,%10111010
db %10000010,%10000010
db %10101010,%10101010
db %10000010,%10000010
db %01111100,%01111100
db %00000000,%00000000
end
display /d,end-begin
savesna "!stack_pat_fs.sna",begin
ld hl,$5800:call draw
ld a,3:out ($FE),a
call anim ;сдвиг узора
ld a,6:out ($FE),a
jp lp
anim:
ld ix,pat
ld b,8
a_lp:
xor a
rr (ix+0) ;циклический сдвиг одной линии узора
rr (ix+1)
jr nc,nob7
set 7,(ix+0)
nob7:
inc ix,ix
djnz a_lp ; повторить 8 раз
ret
10 FOR n=0 TO 6911: POKE 16384+n,PEEK n: NEXT n
device zxspectrum128
ORG #6000
begin
di
jr $
ld sp,$4002
ld hl,$0103
push hl
jr $
end
display /d,end-begin
savesna "!void.sna",begin
pat:
db %01111100,%01111100
db %10000010,%10000010
db %10111010,%10111010
db %10000010,%10000010
db %10101010,%10101010
db %10000010,%10000010
db %01111100,%01111100
db %00000000,%00000000
ld sp,pat
pop hl,de,bc,af
exx
exa
pop hl,de,bc,af
exx
exa
ld sp,$5000;новый указатель памяти на конец экранной
памяти
dup 128
push hl
edup
device zxspectrum128
ORG #6000
begin
zz:
ei
halt
ld a,0
out ($FE),a
ld (back_sp+1),sp
n=0
dup 8+8+8
ld sp,$5800+n*32+15
pop af,bc,de,hl
exx:exa
pop af,bc,de,hl
inc sp
push hl,de,bc,af
exx:exa
push hl,de,bc,af
ld sp,$5800+n*32
pop af,bc,de,hl
exx:exa
pop af,bc,de,hl
inc sp
push hl,de,bc,af
exx:exa
push hl,de,bc,af
n=n+1
edup
back_sp:ld sp,0
; нарисовать линию узора XOR
; один недостаток - при сдвиге эта линия заливается трешем
ld hl,$5800
ld b,24
ld de,32
mm:
ld a,0
xor b
and 7
ld c,a
add a,a
add a,a
add a,a
or c
ld (hl),a
add hl,de
djnz mm
ld hl,mm+1
inc (hl)
ld a,7
out ($FE),a
jp zz
end
display /d,end-begin
savesna "gr8z.sna",begin