2009-09-25 3 views
35

화면의 테두리 부분에 스프라이트를 보여주는 멋진 C64 데모를 보았습니다. 그것은 가능해서는 안됩니다. 나는 그들이 어떻게 든 그래픽 칩을 속일 수 있었다고 생각한다. 그들은 정확히 그것을 어떻게 했습니까?C64의 경계에 스프라이트를 어떻게 표시합니까?

+0

허용되는 스프라이트 이상을 얻으려면 TV 재생 빈도와 관련하여 스프라이트를 충분히 빠르게 움직여야합니다. 즉, 스프라이트가 A 위치의 스크린에 그려지고 B 위치로 이동 한 다음 다시 그려지며, TV 화면이 그려지면 A 지점으로 돌아가거나 A 지점으로 이동했습니다. –

+4

방금 ​​흥미로운 태그 목록에 c64를 추가했습니다. +1! –

+0

이 더 큰 형제 (자매?)인데 아미가 (Amiga)는 스크린 래스터 라인에서 비디오 하드웨어 변경 사항을 정의하기 위해 전체 보조 프로세서 (구리선)를 추가했습니다. 복잡한 어셈블리 인터럽트 프로그램에 대한 필요성 제거 – Toad

답변

27

예, 어셈블러가 필요합니다. 그것은 인터럽트 타이밍 트릭입니다. VIC는 경계에 스프라이트를 표시 할 수 있지만 프레임은 스프라이트를 숨기고 있기 때문에 스프라이트가 뒤에 표시 될 수 있습니다. VIC가 표시하는 주사선에 연결됩니다. 아래쪽/위쪽 테두리는 매우 간단합니다.

  • 인터럽트를 프로그래밍하고 특정 주사선에서 시작하여 7 픽셀 또는 아래쪽 테두리보다 먼저 시작하도록 동기화합니다.
  • 경계를 더 작게 만들려면 VIC에 레지스터를 설정하십시오. (이를 수행 할 수있는 레지스터가 있습니다.)
  • VIC는 이제 경계가 이미 시작되었으며 페인트를 시작하지 않는다고 생각합니다.
  • -> 하단에는 테두리가 없습니다.
  • 실제 경계 다음에 다른 인터럽트를 프로그래밍하여 원래대로 되돌립니다. 프로세스가 매 스캔 라인에 대해 반복하기 때문에 왼쪽/오른쪽 테두리에서 스프라이트를 들어

, 그것은 더 복잡 :

  • 을 programm 특정 스캔 라인에서 시작 동기화 인터럽트.
  • 그런 다음 오른쪽 테두리 앞의 7 픽셀이 될 때까지 일부 NOP를 수행하십시오.
  • 경계를 더 작게 만들려면 VIC에 레지스터를 설정하십시오.
  • -> 오른쪽에 테두리가 없습니다.
  • 실제 경계 다음에 원래의 값으로 되돌릴 때까지 몇 가지 NOP를 수행하십시오.
  • 는 다시 2 단계

문제는이 모든 NOP를가 통화 대기는 당신이 당신의 물건이 사이클을 훔치는 것입니다 때까지 약간의 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 
+0

동료 c64 어셈블리 코더 분명히; ^) – Toad

+0

0xC148의 "init VIC"코드는 주로 스프라이트 스크롤러의 테두리에 스프라이트를 설정한다고 생각합니다. (테두리를 비활성화하는 것과 관련이 있습니다.)하지만 스프라이트는 그렇지 않으면 VIC/래스터 라인의 타이밍이 다르며 모든 것이 작동하지 않습니다. 그리고 어쨌든 스프 라이트가되고 싶습니다 :-) –

1

오래 전이었습니다.

나는 모니터의 주파수에 의존하는 해결책이 있다는 것을 알고있다.

CRT를 사용하면 현재 화면이 일반 화면 외부에 있더라도 현재 픽셀을 알 수 있습니다. 그럼 광선을 조작 할 수 있습니다.

내 Junkpile의 어딘가에 C64 서적이 있어야합니다.

Offtopic이지만 VIC20 (C64의 전신) 그래픽은 재미있었습니다. 각 픽셀을 조작 할 방법은 없었지만 기존 문자를 변경할 수있었습니다. 따라서 0부터 ...까지의 모든 문자로 화면을 채우고 픽셀을 화면으로 설정하도록 문자를 변경했습니다. ;-).

+1

또한 C64에서는 단순히 픽셀을 변경하는 것이 아닙니다. 그래픽 모드는 기본적으로 0, 1, ... 문자로 채워진 문자 모드 화면을 에뮬레이션했습니다. :-) – peterh

9

모두 타이밍에 의존합니다. C64에는 스크린을 그릴 때 전자빔의 정확한 수직 위치를 묻는 방법이있었습니다. 새로운 라인이 시작될 때, 몇 사이클을 기다려야한다. (NOP 명령을 사용하여 시간을 낼 수있다.) 그런 다음 스크린 모드와 테두리 너비를 설정하는 비디오 칩의 하드웨어 레지스터를 설정해야한다. 정확하게 타이밍을 맞추고 모든 스캔 라인을 다시 수행하면 전체 측선이 사라집니다.

하단 경계선이 비슷한 트릭으로 사라졌습니다. 수직 경계가 시작된 정확한 주사선에서 해당 프레임의 아래쪽 경계선을 비활성화 한 비디오 모드를 설정해야했습니다.

실제로이 모든 작업은 어셈블리에서 수행해야했습니다. 그렇지 않으면 정확한 타이밍을 얻을 수 없습니다.

사이드 노트로, 나는 sideborder 트릭이 1001 Crew (네덜란드 그룹)에 신용되었다고 생각한다. 나는 첫번째 밑바닥 국경 간계를 누구가 뽑았는지 확실하지 않다.

+0

$ d012는 현재 래스터 드로이드입니다 ... – BerggreenDK

+0

네,하지만 화면 모드를 변경하기 위해 설정해야하는 레지스터가 아닙니다. – Toad

+0

알아요,하지만 당신은 오히려 "불특정"이라고 썼습니다. 그래서 몇 가지 세부 사항을 추가하고 싶었습니다. 나는 $ d011이 당신이 국경 계약을 맺지 않았는지를 25 줄 또는 24 줄을 사용한다면 선택했다고 생각한다. http : //en.wikipedia.org/wiki/MOS_Technology_VIC-II – BerggreenDK

0

타이밍이 핵심이었습니다. CRT의 빔이 왼쪽에서 오른쪽으로 이동함에 따라 오버 스캔 (테두리) 색을 변경하여 테두리에 이미지가 만들어졌습니다. 이미지를 생성하는 데 필요한 두 개의 타이밍 신호, 즉 수직 새로 고침과 수평 새로 고침이 있습니다. 수평 및 수직 새로 고침이 발생할 때를 감지하여 일련의 어셈블러 명령어를 시작하여 테두리 색상을 변경하여 이미지를 생성 할 수 있습니다. 보더 픽셀 당 CPU 클럭 틱의 수를 계산하고이를 사용하여 오른쪽 포인트의 보더 컬러를 변경하는 코드를 생성해야합니다.

게임을 작성할 때 CPU 오버 헤드가 너무 커서 사용자 입력 및 게임 상태를 처리하는 시간이 너무 길면 잘 작동하지 않습니다.

+0

이것은 완료된 방법이 아닙니다 ... 프로세서가 너무 느려서 색을 빠르게 바꿔서 모든 픽셀 만 밝힐 수 있습니다. 기껏해야. 국경을 제거하는 방법은 국경이 시작/중지되고 디스플레이 모드를 변경하는 정확한 순간을 정하는 것이 었습니다. (내 대답을 참조하십시오) – Toad

+0

난 그냥 몇 가지 계산을 완료했습니다 : 프레임 250 라인에서 25 프레임은 초당 6250 라인 또는 라인 0.00016 초입니다. 1Mhz에서 이것은 160 가지의 명령이므로이 방법을 사용하여 얻을 수있는 가장 많은 부분은 화면에서 160 픽셀입니다. 나는 경계에서 이처럼 끝내게되는 이미지를 보았다. 그리고 그들은 아주 완고했다. – Skizz

+0

화면의 폭은 320 픽셀뿐입니다. –

6

C64에서 테두리를 여는 주제에 대한 좋은 자습서를 보려면 C=Hacking Issue 6의 Pasi Ojala의 우수 기사를 확인하십시오.

너무 기술지고없이

는 트릭은 25/24 행과 텍스트/그래픽 38분의 40 열 사이를 전환 할 수 있도록하기 위해 VIC 칩의 기능을 사용하고 가에 대한 정확한 적당한 순간에이 스위치를 만드는 포함 VIC 을 바보짓으로 말하면서 이미 실제로 국경을 바꿨다고 생각하면 은 없습니다. 코드 예제가있는 에 대한 자세한 설명은 위의 문서를 참조하십시오.