Просмотр полной версии : Использование стека и прерывания
Почитав замечательную статью (http://zxpress.ru/article.php?id=11231) в журнале DeJa Vu #0A "Программирование - быстрая процедура печати спрайтов через стек от WoodlandStudio." - решил попробовать реализовать. В итоге получаю видеоэффекты и зависание после секунд работы.
Суть моей задачи такова. Для примера на прерываниях висит музыка и кое какой вывод графики стеком. Всё работает.
Eсть необходимость "читать" через стек данные из памяти в регистр DE во время прерывания... И тут наступают грабли.
Для примера соорудил код:
INT_VECTOR=#BE00
INT_HANDLER=#BFBF
STACK_MAIN=#7FFF
STACK_IM2=INT_HANDLER-1
ORG #8000
START:
DI
LD SP,STACK_MAIN
LD HL,INT_VECTOR
LD BC,#00BF
LD (HL),C
INC HL
DJNZ $-2
LD (HL),C
LD A,INT_VECTOR/256
LD I,A
IM 2
EI
MAIN_LOOP:
; тут читаем стеком данные из памяти и кидаем на экран для примера
; EI:HALT тут нет, т.к прерывание должно приходить во время работы чтения стеком.
;Если LD SP,SPR1 закоментить зависать перестает, но ясно что выводит мусор :)
LD (STK1+1),SP
LD SP,SPR1
LD HL,#4000
DUP 16
POP DE
LD (HL),E
INC HL
LD (HL),D
INC HL
EDUP
STK1 LD SP,#0000
JP MAIN_LOOP
SPR1 DS #20,#FF
MAIN_ISR:
PUSH IX
PUSH HL
PUSH DE
PUSH BC
PUSH AF
EXX
EX AF,AF'
PUSH IY
PUSH HL
PUSH DE
PUSH BC
PUSH AF
; тут музыка и графика стеком выводится
POP AF
POP BC
POP DE
POP HL
POP IY
EX AF,AF'
EXX
POP AF
POP BC
POP DE
POP HL
POP IX
RET
; Обработчик прерываний
ORG INT_HANDLER
EX DE,HL
EX (SP),HL
LD (SaveRET+1),HL
EX DE,HL
POP DE
LD (SaveSP+1),sp
LD SP,STACK_IM2
CALL MAIN_ISR
SaveSP LD SP,#0000
EI
SaveRET JP #0000
В чём же может быть проблема? :( Что-то к вечеру совсем не соображу...
Вроде помогло...)) Шо это было?)))
Если прерывания разрешены (EI перед Main Loop), и SP не имеет свободной области под указываемым им адресом - то гайки. Если читаемый буфер SPR1 односторонний или постоянно обновляемый в тех же прерываниях, то достаточно освободить немного места перед его началом, как сказал krt17. Кстати, там точно нужны 2 команды EX DE,HL ?
Как я понял, у каждого спрайта, который будет выводиться таким способом первые два байта нужно резервировать. так?
Т.к. прерывание может подпортить любые его четыре байта во время вывода на экран.
В моём случае вроде ничего не портится, полоска выводится непрерывно. Глюков в ней нет. Два байта в начале запарываются, но там можно всегда нули держать на такой случай.
krt17,
Не догнал, что там это даст?
ld hl,spr1
ld e,(hl)
inc hl
ld d,(hl)
inc hl
ld sp,hl
ld hl,#4000
Да, я поправил свое сообщение, но написал все в общих словах, интересно все равно - не совсем понял задачу, которая была поставлена. Перечитал все еще раз - выводятся НЕ 32 байта #FF, а то, что при каждом прерывании обработчик записывает в буфер SPR1?
И нужны ли EX DE,HL ?
Да, я поправил свое сообщение, но написал все в общих словах, интересно все равно - не совсем понял задачу, которая была поставлена. Перечитал все еще раз - выводятся НЕ 32 байта #FF, а то, что при каждом прерывании обработчик записывает в буфер SPR1?
И нужны ли EX DE,HL ?
Пример в топике - отладка алгоритма. В Main_loop будет цикл задач. Одна из которых должна рисовать локации на экране таким способом.
И нужны ли EX DE,HL ?
Да, нужны. Без них не работает :)
При разрешенных прерываниях будут портится спрайты, если только не сделать синхронизацию с прерываниями так, чтобы на момент прихода прерывания, спрайты уже все были напечатаны.
А... все понятно, у вас как бы восстановление в обработчике INT'a )
для понимания процесса рекомендую разобраться самому, думать это же приятно :v2_dizzy_roll:.
Сколько уже напридумывал, сам в шоке :) Суть в общем-то ясна :v2_dizzy_tired2:
Чудненько работает:
ld hl,SPR1
ld e,(hl)
inc hl
ld d,(hl)
inc hl
ld sp,hl
ld hl,#4000
DUP 16
LD (HL),E
INC HL
LD (HL),D
INC HL
POP DE
EDUP
Этот способ хорош, чтобы дергать расчитанные адреса экрана из таблиц циклом)
drbars,
interrupt
di
ex (sp),hl ;забираем со стека адрес возврата
ld (imret),hl ;сохраняем адрес возврата
pop hl ;забираем hl
ld (imstek),sp ;сохраняем стек
push bc ;либо push de в зависимости от того каким регистром берем спрайты
ld sp,int_sp
call proc_int
ld sp,$
imstek equ $-2
ei
jp $
imret equ $-2
;процедура вывода спрайта
;hl откуда
;de куда
;в bc будут данные
ld (retsp),sp
;забираем первое слово
ld c,(hl)
inc hl
ld b,(hl)
inc hl
ld sp,hl
;---------------
;манипулируем
;---------------
ld sp,$
retsp equ $-2
ret
как то так
Я уже запилил как было в первом посте, как понял где баг. Мне с DE выгоднее работать.
нынче замедлять код модно? обработчик из 1 поста оптимальный, не надо его трогать, ну или по крайней мере так трогать
этот обработчик сочинил AlCo он более универсальный
все зависит от того для чего надо
у Медногова
после передачи данных их hl в sp
есть конструкция
ld h b
ld l c
что как бы тоже потери тактов
еще совет раз решил заморочится графикой через стек, inc hl в конкретной ситуации можно менять на inc l это 2 такта на байт в данном случае почти на 10 % быстрее
INC L не всегда реально использовать. У меня таблица адресов не кратна 256, немного больше... на 32 байта кажется.
drbars, ecли на четном адресе живет то можно один inc hl заменить на inc l
Нет, я вот что не понимаю:
Произошло прерывание, надо снять адрес возврата со стека, и сохранить его на будущее. Так как там будет JP по адресу, со стека адрес надо снять, но не испортив регистров.
EX DE,HL
EX (SP),HL
LD (SaveRET+1),HL
EX DE,HL
POP DE
Адрес сохранен, регистры на своих местах, SP как был до прерывания.
А если вот так:
EX (SP),HL
LD (SaveRET+1),HL
POP HL
Меньше на 2 команды и быстрее на 8 тактов. Разве не то же самое делает?..
Во втором случае ты восстанавливаешь HL ведь. Этот регистр не очень удобен в работе. Процедура обработки прерывания позволяет восстанавливать только один из регистров во время снятия данных стеком.
Во втором случае ты восстанавливаешь HL ведь.
Хм, я, наверное, не то курю, но на мой взгляд после обоих вариантов все регистры остаются на своих местах (кроме SP, который в обоих вариантах на 2 больше чем на входе, т.е. опять же такой, как был до сигнала прерывания). Поэтому, как кажется, неважно, что восстанавливать - главное, чтобы в итоге было восстановлен все. При то, что во втором варианте код короче и быстрее.
Процедура обработки прерывания позволяет восстанавливать только один из регистров во время снятия данных стеком.
Почему один? EX (SP),HL сохраняет HL на стеке, POP HL его восстанавливает. DE и все остальное, кроме SP, не изменяются на всем протяжении, потому что потом идет PUSH всех, а в конце POP всех и прямой JP на адрес возврата. Там ничего не должно теряться в обоих вариантах.
TomCaT, ты абсолютно прав
но тема здесь немного другая
необходимо после восстановления адреса возврата и стека
восстановить испорченную память что мы и делаем обновляя ее DE у медноногова
и push reg у AlCo
EX DE,HL
EX (SP),HL
LD (SaveRET+1),HL
EX DE,HL
POP DE
LD (SaveSP+1),sp
LD SP,STACK_IM2
CALL MAIN_ISR
SaveSP LD SP,#0000
EI
SaveRET JP #0000
ex (sp),hl ;забираем со стека адрес возврата
ld (imret),hl ;сохраняем адрес возврата
pop hl ;забираем hl
ld (imstek),sp ;сохраняем стек
push bc ;либо push de в зависимости от того каким регистром берем спрайты
ld sp,int_sp
call proc_int
ld sp,$
imstek equ $-2
ei
jp $
imret equ $-2
:v2_dizzy_facepalm:
Вот же, обработчик по сути рассчитан на то, что в DE то же, что было в (SP-2) до прихода прерывания...
Все, понял, спасибо. Хитро-о, однако.
:v2_dizzy_facepalm:
Хитро-о, однако.
Не то слово, но зато теперь со всем разобрались и можно применить в реальном проекте :v2_dizzy_roll:
ws_mason
12.12.2012, 17:36
Кстати, статья моя (потупив взгляд). Печать спрайта выковыряна из Черного Ворона, а работу с регистром ВГ сам ваял.
Вот пример использования печати спрайта http://zx.pk.ru/showpost.php?p=32815&postcount=60
Эх, мало толку от этого метода...
Придумал вывод только таким способом пока:
LD HL,TEST_SPR
LD E,(HL)
INC HL
LD D,(HL)
INC HL
LD (STK1+1),SP
LD SP,HL
LD HL,#C000
LD B,#10
LOOP1 LD A,L
DUP 16
LD (HL),E ; 7t
INC L ; 4t
LD (HL),D ; 7t
POP DE ; 10t
INC L ; 4t
EDUP
LD L,A
; на пересылку 2-х байт уходит 7+4+7+10+14=32 такта
; LDI — те же 16 таков, да и использовать LDI тут не получится :(
INC H
LD A,H
AND #07
JR NZ,LOOP2
LD A,L
SUB #E0
LD L,A
SBC A,A
AND #F8
ADD A,H
LD H,A
LOOP2 DJNZ LOOP1
STK1 LD SP,#0000
Вот такой способ уже не получается:
DE — восстанавливать нельзя!
POP DE
LD A,E
OR OFFSET
LD E,A
DUP 32
LDI
EDUP
Powered by vBulletin® Version 4.2.5 Copyright © 2026 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot