Сообщение от
atariki
ну вот допустим захотел я джойстиком погонять точку по экрану в gr.0, как мне логически рассуждать в ассемблере для написания этой программы ?
Добрый денёк, atariki.
Ну, чтобы пиксель гонять по экрану, надо объединить графику 0 с графикой 8.
Это сделать можно, но там свои проблемы...
А вот, чтобы погонять знакоместо (курсор) по экрану в ДОСе, могу предоставить ассемблерную программку...
Рассуждаем следующим образом...
1) Что гоняет курсор по экрану?
- При нажатии на клаве стрелки, код клавиши идёт в системную программу преобразования кодов в буквы(ATASCII) и окончательно оседает в однобайтовом теневом буфере ввода CH.
Таким образом, зная коды стрелок и анализируя положение джойстика, мы можем руководствуясь джойстиком, по нашему желанию подменять коды в регистре CH. Тогда при следующем VBI, наши коды будут двигать системный курсор.
2) Когда подменять коды в CH?
- Так как машинка не должна знать, что мы подменяем коды, надо делать это в прерывании по Вертикальному Бланку (по кадрам экрана).
3) Где поместить программу VBI?
- Программка достаточно короткая (~40 байт), чтобы быть помещена где угодно!!! В частности, я помещал её в конце аппаратного стека и стек никогда её не затирал.
4) Какой режим VBI выбрать?
- Я выбрал Immediate, так как у этого режима около 60 свободных циклов, но можно и Deferred - без разницы.
5) Какой будет скорость курсора?
- Нормальная для меня скорость курсора это считывание данных джойстика каждый пятый кадр экрана. (Счётчик кадров должен меняться от 4 до 0). Большие значения счётчика замедляют движение.
А вот и сама программа.
Код:
; Джойстик-курсор
; jc.com
.ou jc.com
; ====================
; Ярлыки
SETVBV = $e45c ; Вектор установки VBI.
SYSVBV = $e45f ; Возврат на системный VBI.
STICK0 = $0278 ; Теневой регистр джойстика.
RUNAD = $02e0 ; Адрес запуска программы
CH = $02fc ; Теневой буфер текстовых кодов
; --------------------
; Константы
vbmode = 6 ; Режим VBI=Immediate
speed = $04 ; Скорость курсора.
cur.up = 142 ; Величины кодов стрелок...
cur.dn = 143
cur.lt = 134
cur.rt = 135
; ====================
; Главная программа
.or $0110 ; Конец стека
start jmp init ; Переход на подпрограмму инициализации
; прерывания по VBI
; --------------------
; Блок данных
keytab .by cur.up,cur.dn
.by cur.lt,cur.rt
counter .by 2
; --------------------
; Инициализация прерывания VBI
init
ldy #<vbi ; LSB исполняемой части VBI
ldx #>vbi ; MSB исполняемой части VBI
lda #vbmode ; Режим VBI
jsr SETVBV
;
rts ; Возврат в ДОС после инициализации VBI
; ====================
; Подпрограмма исполняемой части VBI
vbi
dec counter ; Уменьшаем счётчик пропуска считываний джойстика.
bne done ; Если не дошел до нуля,
; переходим на системный VBI.
lda #speed ; Если ноль,..
sta counter ; обновляем счётчик пропуска считываний джойстика.
;
lda STICK0 ; Затем, считываем джойстик
eor #$0f ; Проводим проверку на движение ручки.
; Число $0f равно 15, а это значение, если ручка НЕ ДВИГАЛАСЬ!
; eor (Исключающее ИЛИ) ИНВЕРТИРУЕТ данные в Аккумуляторе и
; в случае, если там было 15, станет 0.
; При анализе положения ручки будут исследоваться уже ИНВЕРТИРОВАННЫЕ данные!!!
beq done ; Если ноль, джойстик не двигался и мы
; переходим на системный VBI.
;
ldx #$ff ; Если двигался, устанавливаем в 255 (reset)
; селектор считывания таблицы кодов стрелок.
; По сути - это смещение в регистре X.
chkstk
inx ; Чтобы перейти к следующему значению в таблице,
; увеличиваем смещение.
; В случае, если мы реинициализировали селектор,
; вспоминаем, что в однобайтных вычислениях $ff+$01=$00,
; то есть смещение равно нулю и селектор показывает
; на первое значение в таблице.
lsr a ; Так как в аккумуляторе у нас ИНВЕРТИРОВАННОЕ значение
; данных джойстика, сдвинем логически биты вправо.
; При этом сдвинутый бит помещается во флаг статуса Carry.
bcc chkstk ; Если в Carry ноль, значит в этом направлении
; джойстик не двигался, проверяем следующее направление...
lda keytab,x ; Если движение было, берём соответствующее значение
; данных курсора из таблицы
sta CH ; и заносим их в теневой буфер CH
done
jmp SYSVBV ; переходим к системному VBI.