Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

Да, вам нужен ассемблер. Это временный трюк прерывания. VIC может отображать спрайты на границе, но кадр просто скрывает их, поэтому спрайты могут скользить позади него. Он подключен к линиям сканирования, отображаемым VIC. Для нижних/верхних границ это довольно просто:

  • Запрограммируйте прерывание, синхронизированное для запуска с определенной строки сканирования, 7 пикселей или что-то подобное до нижней границы.
  • Установите регистр в VIC, чтобы уменьшить границу. (Существует регистр, который может это сделать.)
  • 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

Ответ 2

Все полагалось на сроки. У C64 был способ запросить точное вертикальное расположение электронного луча, когда он рисовал экран. Когда началась новая строка, вам пришлось подождать несколько циклов (вы могли бы это время использовать с помощью инструкции NOP), а затем вам пришлось установить аппаратный регистр видеочипа, который отвечал за настройку экранного режима (и ширины границы). Справив его точно так же, и снова выполнив каждую строку сканирования, весь боковой борд исчез.

Нижняя граница ушла с подобным трюком. На точной строке сканирования, где началась вертикальная граница, вам также пришлось установить видеомод, который отключил нижнюю границу для этого кадра.

Действительно, все это должно было быть сделано в сборке. В противном случае вы никогда не сможете точно определить время.

В качестве побочной заметки, я думаю, что трюк со стороны был зачислен в 1001 Crew (голландская группа). Я не уверен, кто снял первый трюк с нижней границей.

Ответ 3

Для хорошего учебника по теме открытия границ на C64, проверьте Pasi Ojala отличную статью в C = Hacking Issue 6.

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

Ответ 4

Это давно.

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

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

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

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

Ответ 5

Сроки были ключом. Изображение было создано на границе, изменив цвет overscan (border), поскольку луч CRT перемещается слева направо. Для создания изображения требуются два временных сигнала: вертикальное обновление и горизонтальное обновление. Определив, когда происходит горизонтальное и вертикальное обновление, вы можете запустить последовательность инструкций ассемблера, чтобы изменить цвет границы для создания изображения. Вам нужно определить количество тактовых импульсов ЦП на пограничный пиксель и использовать его для создания кода, который изменяет цвет границы в правой точке.

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