繁体   English   中英

C64上的稳定栅格

[英]Stable raster on C64

在Commodore 64上使用6510程序集,我试图创建一个稳定的光栅效果。 使用双IRQ原理我在屏幕上绘制一些光栅线。 我用NOP填充以匹配每个正常扫描线的63个循环,并且每个标记线匹配23个循环。 我意识到我需要设置一个特定的起始线,以便将我的第8次迭代与坏线相匹配,但无论我放在第一行的哪一行或我使用的NOP的组合,我都无法得到时机正确。 我想要完整的线条,而不是“破碎”。 谁能看到我做错了什么? 代码采用Kick Assembler格式。 这是一个截图:

截图

.pc = $0801 "Basic upstart"
:BasicUpstart($8000)

.pc = $8000 "Program"

  jsr $ff81

  sei
  lda #$35
  sta $01

  jsr setupInterrupts
  cli

  jmp *

setupInterrupts:
  lda #<int1
  ldy #>int1
  sta $fffe
  sty $ffff

  lda #$01
  sta $d01a
  lda #$7f
  sta $dc0d
  sta $dd0d
  lda $dc0d  
  lda $dd0d
  lda #$1b
  sta $d011
  lda #$01
  sta $d019

  lda start
  sta $d012

  rts

start:
  .byte 56

int1:
  pha txa pha tya pha

  :STABILIZE()

.for (var i=0; i<7; i++) {
  inc $d020   // 6 cycles
  inc $d021   // 6 cycles
  nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop // 24*2=48 cycles
  bit $ea     // 3 cycles
              // = 63 cycles
}
  inc $d020   // 6 cycles
  inc $d021   // 6 cycles
  nop nop nop nop // 4*2=8 cycles
  bit $ea     // 3 cycles
              // = 23 cycles (badline)

  lda #$00
  sta $d020
  sta $d021

  lda start
  sta $d012

  lda #<int1 
  ldy #>int1 
  sta $fffe
  sty $ffff

  lda #$01
  sta $d019

  pla tay pla tax pla

  rti


.macro STABILIZE() {

  lda #<nextRasterLineIRQ
  sta $fffe
  lda #>nextRasterLineIRQ
  sta $ffff   

  inc $d012

  lda #$01
  sta $d019

  tsx

  cli

  nop nop nop nop nop nop nop nop

nextRasterLineIRQ:
  txs

  ldx #$08
  dex
  bne *-1
  bit $00

  lda $d012
  cmp $d012

  beq *+2      
}

据我了解你的问题不是你的光栅条闪烁(即你的光栅中断是稳定的),而是你在屏幕上绘制的光栅条的第二行不是完全红色。

你的问题是坏线。 (见[1])

使用发布的代码稳定光栅中断后,“实际代码”将在光栅线$ 3A的周期4开始运行。

光栅条的第二行,您想要背景颜色,边框颜色为红色,是一条坏线。 (这是光栅线$ 3B。由于$ D011 = $ 1B,这是一个坏线,因为$ D011和$ D012的低3位是相同的)

在这条坏线上,第一个INC(INC $ D020)设法运行,因此边框颜色变为红色。 然后第二个INC(INC $ D021)开始运行,但VIC在它完成之前接管,因此你的INC $ D021因此在VIC返回总线之后才完成。 (这是43个循环之后 - 即将背景颜色设置为红色延迟43个循环)。

你几乎拥有它,但是badline与你的代码预期的光栅线不同,你需要“推几个周期”,以便在被VIC中断之前,两个INC都将在坏线上执行。 (如果你想在VIC接管之前执行这两个INC,那么在坏线的第4周期开始执行两个INC有点太晚了)

更新示例:

尝试替换代码的这一部分:

.for (var i=0; i<7; i++) {
  inc $d020   // 6 cycles
  inc $d021   // 6 cycles
  nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop // 24*2=48 cycles
  bit $ea     // 3 cycles
              // = 63 cycles
}

  inc $d020   // 6 cycles
  inc $d021   // 6 cycles
  nop nop nop nop // 4*2=8 cycles
  bit $ea     // 3 cycles
              // = 23 cycles (badline)

有了这个:

// a delay to get to some cycle at the end of the raster-line, so we have time to execute both inc's on 
// each successive raster-line - in particular on the badlines before the VIC takes over the bus.
.for (var i=0; i<28; i++) nop

// just for illustrative purposes - not cool code :)
.for (var i=0; i<8*6; i++) {
  inc $d020   // 6 cycles
  inc $d021   // 6 cycles
  .if ([i & %111] == 0) {
      // badline
      nop nop nop nop // 4*2=8 cycles
  } else {
      // non-badline
      nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop // 24*2=48 cycles
      bit $ea     // 3 cycles
                  // = 63 cycles
  }
}

(警告:此代码在内存方面相当浪费 - 使用正常循环可以轻松实现相同的效果)(而不是改变延迟,您可以通过修改$ D011,如果你没有,可以将坏线推开)计划显示人物图形)

尝试检查HOXS64仿真器中的机器代码监视器。 它非常适合调试与时序相关的问题。 它显示您在任何给定时间哪个光栅线的循环(+它可以在中断时中断)。

希望这有助于:)


注意,我还没有仔细查看你的稳定光栅例程中的陷阱,但似乎没问题 - 方法是正确的,你没有任何闪烁。 如果你开始得到闪烁的光栅条,你知道要修复什么。 ;)


如果有人读这个不知道什么是坏线:

酷参考:

[1]:阅读更多关于vic-article中的“坏线”(或称为“vic-bible”,因为它应该被称为): http ://csdb.dk/release/?id = 44685(PDF)或http://vice-emu.sourceforge.net/plain/VIC-Article.txt(TXT )。 另见附录: http//vice-emu.sourceforge.net/plain/VIC-Addendum.txt

基本上,当VIC芯片开始绘制文本行的第一个光栅线时,它会从CPU中窃取40-43个周期(见下文为什么不总是43个)。 这些栅格线称为“坏线”。 因此,在坏线上只有20-23个可用循环,而不是63个循环。

(更确切地说,当$ D011的3个最低位等于$ D012的3个最低位时(并且我们不在边界并且屏幕未被$ 4的第4位“关闭”),会发生错误线。 D011))

VIC芯片使用这43个周期中的最后40个来读取要在文本行上显示的40个字符。 在这40个周期内,CPU无法执行任何指令。

然而,在这43个周期的前3个周期中,CPU实际上可以执行其指令的“写周期” - 但只能写周期,而不是读周期。 (参见[2])因此,如果您正确计算您的操作码,您可以在这3个周期内执行指令的某些周期。 (注意:具有3个写周期的唯一指令是“brk”,这通常是无用的,因此在实践中,您将只能使用这3个周期中的最多2个有用的东西)。

请注意,除了在坏线上窃取周期之外,VIC还会在具有精灵的栅格线上从CPU中窃取周期。

[2]:请参阅“64doc”以了解C64的不同指令的哪些周期是写周期: http//vice-emu.sourceforge.net/plain/64doc.txt
(写周期在表中标记为“W”,读周期标记为“R”)

[X]: ......在http://codebase64.org上有很多好文章

为了使光栅线无闪烁,需要一些额外的技巧来稳定时序。 原因是,您永远无法确定您的光栅例程是否在行的最开始执行,但取决于CPU“离开”主程序代码的位置,浪费了未知量的周期来执行最后一个操作。 有不同的方法来实现这一目标,您应该在Codebase64上查看页面以了解有关此主题的更多信息并获取一些示例代码。 但是,一旦你建立了一个稳定的光栅时间,你的方法对我来说很好。

如果我没记错的话(从20多年前开始)..

由于较小的中断抖动,不太可能获得完全稳定的光栅效果时序; 所以无论你在软件中做什么,你都会在扫描线的开头有一个“闪烁”点。

要解决这个问题,请使用精灵来隐藏闪烁点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM