C64上的稳定栅格

Kri*_*lén 12 assembly 6510

在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      
}
Run Code Online (Sandbox Code Playgroud)

Bja*_*rke 13

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

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

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

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

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

你几乎拥有它,但是badline与你的代码预期的光栅线不同,你需要"推几个周期",这样两个INCs都会在被VIC中断之前在坏线上执行.(如果你想在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)
Run Code Online (Sandbox Code Playgroud)

有了这个:

// 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
  }
}
Run Code Online (Sandbox Code Playgroud)

(警告:此代码在内存方面相当浪费 - 使用正常循环可以轻松实现相同的效果)(您可以通过修改$ 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"in表和读周期标记为"R")

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