我如何在C64的边界显示精灵?

我已经看到很酷的C64演示,在屏幕边框显示精灵。 这是不可能的; 我认为他们以某种方式欺骗了graphics芯片。 他们到底是怎么做的?

是的,你需要汇编程序。 这是一个中断计时技巧。 维也纳国际中心能够在边界上显示精灵,但框架只是隐藏它们,所以精灵可以在它后面滑动。 它连接到由VIC显示的扫描线。 对于较低/较高的边界很简单:

  • 编程一个中断,同步开始在某个扫描线,7像素或类似的下边界之前的东西。
  • 在VIC中设置寄存器来减小边界。 (有一个registry可以做到这一点。)
  • 国际中心现在认为,边界已经开始,并没有开始绘制。
  • – >底部没有边框。
  • 编程另一个中断后,真正的边界将其设置回原来的。

对于左侧/右侧边界的精灵来说,这更复杂,因为每一个扫描线都必须重复这个过程:

  • 编程一个中断,同步从一个特定的扫描行开始。
  • 然后做一些NOP,直到你在右边界之前7个像素。
  • 在VIC中设置寄存器来减小边界。
  • – >在右侧没有边框。
  • 做一些NOP,直到你在真正的边界之后,把寄存器恢复到原来的值。
  • 再次做一些NOP,直到第2步。

问题是,所有这些NOP都在忙着等待,并偷走你的东西的周期。

我能够从下边界的精灵卷轴中find一些代码。 这是代码。 (这是从一些演示中撕掉。)

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指令来计时),然后你必须设置负责设置屏幕模式(和边界宽度)的video芯片的硬件寄存器。 通过精确计时,再次扫描每一行,整个边界消失了。

底部的边界走了一个类似的伎俩。 在垂直边界开始的确切扫描线上,您也必须设置禁用该帧底部边界的video模式。

事实上,这整个事情必须在大会上完成。 否则,你永远不可能完全正确的时机。

作为一个侧面说明,我认为sideside的把戏被记入1001乘员组(荷兰组)。 我不确定谁拉下了第一个底部的边框技巧。

有关打开C64边框主题的好教程,请查看Pasi Ojala在C = Hacking Issue 6中的优秀文章。

没有太多的技术性,这个技巧使用了VIC芯片的一个特性,让你在25/24行和40/38列的文本/graphics之间切换,并且涉及到在恰当的时机切换这个开关,以欺骗维多利亚中心的想法事实上它已经改变了边界。 查看上面的文章,以获得更全面的解释与代码示例。

那是很久以前的事了

我知道有一个解决scheme,依靠监视器的频率。

使用CRT,即使在正常屏幕之外,当前像素也是已知的。 所以你可以操纵光线。

在我的垃圾堆里有一些C64书籍。

Offtopic,但与VIC20(C64的前身)的graphics很有趣。 没有办法来操纵每个像素,但你可以改变现有的字符。 所以你用从0到…的所有字符填充屏幕,并改变字符设置像素到屏幕上。 ;-)。

时机是关键。 在CRT的光束从左向右移动时,通过改变过扫描(边框)颜色,在边框中创build图像。 产生图像需要两个定时信号 – 垂直刷新和水平刷新。 通过检测何时发生水平和垂直刷新,您可以启动一系列汇编程序指令来更改边界颜色以生成图像。 您需要计算每个边界像素的CPU时钟滴答数,并使用它来创build在右侧点更改边界颜色的代码。

在编写游戏时,它不能很好地工作,因为CPU的开销太大了,没有时间去处理用户input和游戏状态。