Я видел крутые демо C64, показывающие спрайты по краям экрана. Это не должно быть возможно; Думаю, им как-то удалось обмануть графический чип. Как именно они это сделали?
Как показать спрайты на границе на C64?
Ответы (6)
Да, нужен ассемблер. Это трюк с синхронизацией прерываний. VIC может отображать спрайты на границе, но рамка их просто скрывает, поэтому спрайты могут скользить за ней. Он подключен к линиям сканирования, отображаемым VIC. Для нижних/верхних границ это довольно просто:
- Запрограммируйте прерывание, синхронизированное для запуска с определенной строки развертки, 7 пикселей или что-то в этом роде до нижней границы.
- Установите регистр в VIC, чтобы сделать границу меньше. (Есть регистр, который может это сделать.)
- ВИК сейчас считает, что граница уже началась и не начинает ее закрашивать.
- -> Нет границы внизу.
- Запрограммируйте еще одно прерывание после реальной границы, чтобы вернуть ее в исходное состояние.
Для спрайтов в левой/правой границах это сложнее, потому что процесс нужно повторять для каждой строки сканирования:
- Запрограммируйте прерывание, синхронизированное с запуском на определенной строке развертки.
- Затем выполните несколько NOP, пока не окажетесь за 7 пикселей до правой границы.
- Установите регистр в VIC, чтобы сделать границу меньше.
- -> Нет границы с правой стороны.
- Сделайте несколько NOP, пока не дойдете до реальной границы и не верните регистру исходное значение.
- Снова сделайте несколько NOP до шага 2.
Проблема в том, что все эти NOP-операторы заняты ожиданием и крадут циклы, которые у вас есть для ваших вещей.
Мне удалось найти для вас кое-какой код из скроллера спрайтов на нижней границе. Вот код. (Это было вырвано из какой-то демо.)
C198 78 SEI
C199 20 2E C1 JSR C12E # clear sprite area
C19C 20 48 C1 JSR C148 # init VIC
C19F A9 BF LDA #BF # set up IRQ in C1BF
C1A1 A2 C1 LDX #C1
C1A3 8D 14 03 STA 0314
C1A6 8E 15 03 STX 0315
C1A9 A9 1B LDA #1B
C1AB 8D 11 D0 STA D011
C1AE A9 F7 LDA #F7
C1B0 8D 12 D0 STA D012
C1B3 A9 01 LDA #01
C1B5 8D 1A D0 STA D01A
C1B8 A9 7F LDA #7F
C1BA 8D 0D DC STA DC0D
C1BD 58 CLI
C1BE 60 RTS
----------------------------------
# init VIC
C148 A2 00 LDX #00
C14A BD 88 C1 LDA C188,X
C14D 9D 00 D0 STA D000,X # set first 16 values from table
C150 E8 INX
C151 E0 10 CPX #10
C153 D0 F5 BNE C14A
C155 A9 FF LDA #FF
C157 8D 15 D0 STA D015
C15A A9 00 LDA #00
C15C 8D 1C D0 STA D01C
C15F A9 FF LDA #FF
C161 8D 17 D0 STA D017
C164 8D 1D D0 STA D01D
C167 A9 C0 LDA #C0
C169 8D 10 D0 STA D010
C16C A9 F8 LDA #F8
C16E A2 00 LDX #00
C170 9D F8 07 STA 07F8,X
C173 18 CLC
C174 69 01 ADC #01
C176 E8 INX
C177 E0 08 CPX #08
C179 D0 F5 BNE C170
C17B A9 0E LDA #0E
C17D A2 00 LDX #00
C17F 9D 27 D0 STA D027,X
C182 E8 INX
C183 E0 08 CPX #08
C185 D0 F8 BNE C17F
C187 60 RTS
----------------------------------
# data set into VIC registers
C188 00 F7 30 F7 60 F7 90 F7
C190 C0 F7 F0 F7 20 F7 50 F7
----------------------------------
# main IRQ routine
C1BF A2 08 LDX #08
C1C1 CA DEX
C1C2 D0 FD BNE C1C1
C1C4 A2 28 LDX #28 # 40 or so lines
C1C6 EA NOP # "timing"
C1C7 EA NOP
C1C8 EA NOP
C1C9 EA NOP
C1CA CE 16 D0 DEC D016 # fiddle register
C1CD EE 16 D0 INC D016
C1D0 AC 12 D0 LDY D012
C1D3 88 DEY
C1D4 EA NOP
C1D5 98 TYA
C1D6 29 07 AND #07
C1D8 09 18 ORA #18
C1DA 8D 11 D0 STA D011
C1DD 24 EA BIT EA
C1DF EA NOP
C1E0 EA NOP
C1E1 CA DEX
C1E2 10 E4 BPL C1C8 # repeat next line
C1E4 A9 1B LDA #1B
C1E6 8D 11 D0 STA D011
C1E9 A9 01 LDA #01
C1EB 8D 19 D0 STA D019
C1EE 20 00 C0 JSR C000 # call main code
C1F1 4C 31 EA JMP EA31 # finish IRQ
Все зависело от времени. У C64 был метод запроса точного вертикального положения электронного луча во время рисования экрана. Когда начиналась новая строка, нужно было подождать несколько тактов (это можно было засечь с помощью инструкции NOP), а затем нужно было установить аппаратный регистр видеочипа, отвечающий за установку режима экрана (и ширины границы). Точно рассчитывая время и повторяя каждую строку сканирования, вся боковая граница исчезла.
Аналогичным трюком ушла нижняя граница. На той строке сканирования, где начиналась вертикальная граница, вам также нужно было установить видеорежим, который отключил нижнюю границу для этого кадра.
На самом деле все это нужно было делать в сборе. В противном случае вы никогда не сможете точно определить время.
В качестве примечания, я думаю, что трюк с боковой границей был приписан команде 1001 Crew (голландская группа). Я не уверен, кто провернул первый трюк с нижней границей.
Чтобы получить хорошее руководство по теме открытия границ на C64, ознакомьтесь с отличной статьей Паси Ояла в C=Взлом 6.
Не вдаваясь в технические подробности, трюк использует функцию чипа VIC, позволяющую переключаться между 25/24 строками и 40/38 столбцами текста/графики, и включает в себя это переключение в нужный момент, чтобы обмануть VIC и заставить его думать, что это уже включил границы, когда на самом деле это не так. Ознакомьтесь с приведенной выше статьей для более подробного объяснения с примерами кода.
Это было давно.
Я знаю, что было решение, основанное на частоте монитора.
С ЭЛТ текущий пиксель известен, даже если он находился за пределами обычного экрана. Таким образом, вы можете манипулировать лучом.
Где-то в моей куче мусора должно быть несколько книг C64.
Оффтоп, но графика с VIC20 (предшественник C64) была забавной. Не было возможности манипулировать каждым пикселем, но можно было изменить существующие символы. Итак, вы заполнили экран всеми символами от 0 до ... и изменили символы, чтобы установить пиксели на экране. ;-).
Как уже было сказано, вам нужно обмануть ВИК, чтобы он подумал, что граница уже началась, но причина, по которой я пишу это, заключается в том, что верхний ответ немного неточен: я совершенно не смог найти регистр, чтобы сделать границу меньше, поэтому вы делаете это следующим образом (по крайней мере, для верхней и нижней части): вы ждете, пока VIC не достигнет 25-й строки символов, а затем вы включаете 24 строки ($D011, бит 3). Вы можете сделать то же самое для левой и правой границы, только с 38 столбцами ($D016, бит 3), но для этого вам нужно очень точное время, и вам также нужно устранить плохие строки, установив регистр вертикальной прокрутки. , поэтому мод 8 линии развертки никогда не равен значению прокрутки. Конечно, вы больше не можете использовать обычное отображение, потому что плохие строки на самом деле не просто плохие, я думаю, они используются для загрузки символьных данных, которые повторяются для каждой 8-й строки в неграничной области. Лично я был немного сбит с толку, когда прочитал верхний ответ, надеюсь, это поможет. (Кроме того, в верхнем ответе есть ошибка: вы не делаете границу меньше, вы делаете ее больше)
Время было ключевым. Изображение было создано на границе путем изменения цвета границы (границы) по мере того, как луч ЭЛТ перемещался слева направо. Для создания изображения необходимы два синхронизирующих сигнала — обновление по вертикали и обновление по горизонтали. Обнаружив, когда происходит горизонтальное и вертикальное обновление, вы можете запустить последовательность инструкций ассемблера, чтобы изменить цвет границы для создания изображения. Вам нужно рассчитать количество тактовых импульсов ЦП на пиксель границы и использовать это для создания кода, который меняет цвет границы в нужной точке.
Это не очень хорошо работает, когда дело доходит до написания игр, поскольку накладные расходы ЦП слишком велики, чтобы можно было увеличить время для обработки пользовательского ввода и состояния игры.