Как показать спрайты на границе на C64?

Я видел классные демонстрации C64, показывающие спрайты в пограничной области экрана. Это не должно быть возможно; Я думаю, что им удалось как-то обмануть графический чип. Как именно они это сделали?

5 ответов

Решение

Да, вам нужен ассемблер. Это трюк с синхронизацией времени. 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 = Hacking Issue 6.

Не вдаваясь в технические подробности, уловка использует особенность чипа VIC, позволяющую переключаться между 25/24 строками и 40/38 столбцами текста / графики, и включает в себя переключение в нужный момент, чтобы обмануть VIC и подумать об этом. уже изменил границы, когда на самом деле это не так. Проверьте вышеупомянутую статью для более подробного объяснения с примерами кода.

Это давно.

Я знаю, что было решение, которое основывалось на частоте монитора.

С помощью ЭЛТ текущий пиксель известен, даже если он был за пределами обычного экрана. Чтобы ты мог манипулировать лучом.

Где-то в моем барахле должно быть несколько книг C64.

Оффтоп, но графика с VIC20 (предшественником C64) была веселой. Не было никакого способа манипулировать каждым пикселем, но вы могли изменить существующие символы. Таким образом, вы заполнили экран всеми символами от 0 до... и изменили символы, чтобы установить пиксели на экране.;-).

Как уже было сказано, вы должны обмануть VIC, чтобы он подумал, что граница уже началась, но я пишу это потому, что верхний ответ немного неточен: мне совершенно не удалось найти регистр, чтобы сделать границу меньше, поэтому вы делаете это так (по крайней мере, для верха и низа): вы ждете, пока VIC не достигнет 25-й строки символов, а затем включаете 24 строки($D011, бит 3). Вы можете сделать то же самое для левой и правой границы, только с 38 столбцами ($D016, бит 3), но для этого вам потребуется очень точное время, и вам также необходимо устранить плохие линии, установив регистр вертикальной прокрутки, поэтому мод 8 строки развертки никогда не равен значению прокрутки. Конечно, вы больше не можете использовать нормальный дисплей, потому что плохие строки на самом деле не просто плохие, они используются для загрузки символьных данных, я думаю, вещей, которые повторяются для каждой 8-й строки в безграничной области. Я лично был немного сбит с толку, когда прочитал главный ответ, надеюсь, это поможет. (Кроме того, в верхнем ответе есть ошибка: вы не уменьшаете границу, а делаете ее больше)

Время было ключом. Изображение было создано на границе путем изменения цвета пересканирования (границы) при перемещении луча ЭЛТ слева направо. Для создания изображения требуются два сигнала синхронизации - вертикальное обновление и горизонтальное обновление. Определив, когда происходит горизонтальное и вертикальное обновление, вы можете запустить последовательность инструкций ассемблера, чтобы изменить цвет границы для создания изображения. Вам необходимо определить количество тактов процессора на пиксель границы и использовать его для создания кода, который меняет цвет границы в нужной точке.

Это не очень хорошо работает, когда речь идет о написании игр, так как нагрузка на процессор слишком велика для того, чтобы можно было поднять время для обработки пользовательского ввода и состояния игры.

Другие вопросы по тегам