assembly C64上的稳定光栅

gmxoilav  于 2023-06-30  发布在  其他
关注(0)|答案(4)|浏览(125)

在Commodore 64上使用6510组件,我试图创建一个稳定的光栅效果。使用双IRQ原理,我在屏幕上画了一些光栅线。I垫与NOP匹配63个周期为每个正常的扫描线,和23个周期为每个坏线。我意识到我需要设置一个特定的起始行,以便将我的第8次迭代与badline相匹配,但无论我将第一行放在哪一行,或者我使用的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      
}
bprjcwpo

bprjcwpo1#

据我所知,您的问题不是光栅条 Flink (即您的光栅中断是稳定的),但是您在屏幕上绘制的光栅条的第二行不是完全红色的。
你的问题是线路不好。(参见[1])
在你稳定了你的光栅中断之后,用你发布的代码,你的“实际代码”将在光栅线$3A的周期4开始运行。
光栅条的第二行,您希望背景色和边框颜色为红色,是一条坏线。(这是30亿美元的光栅线。由于$D011 = $1B,这是一条坏线,因为$D011和$D012的低3位是相同的)
在这条坏线上,第一个INC(INC $D020)设法运行,因此边框颜色变为红色。然后,第二个INC(INC $D021)开始运行,但维克在它完成之前接管,因此,您的INC $D021直到VIC归还总线之后才完成。(这是43个周期后的结果-即将背景色设置为红色被延迟43个周期)。
你几乎已经得到了它,但是badline在一个与你的代码预期不同的光栅行上,你需要“推几个周期”,这样两个INC在被维克中断之前都会在badline上执行。(如果您希望在维克接管之前执行这两个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来替换坏行,而不是改变延迟)
尝试检查HOXS 64仿真器中的机器码监视器。它非常适合调试与时序相关的问题。它显示您在任何给定时间处于哪个光栅线的哪个周期(+它可以在中断时中断)。
希望这有帮助:)

  • 注意,我还没有彻底检查你的稳定光栅例程的陷阱,但它似乎是好的-方法是正确的,你没有任何 Flink 。如果你开始得到 Flink 光栅酒吧,你知道该怎么解决。;)*

如果有人阅读这篇文章不知道什么是badlines:

酷引用:
**[1]:**阅读更多关于“坏线”在vic文章(或“vic圣经”,因为它值得被称为):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-chip开始绘制文本行的第一个光栅行时,它会从CPU中窃取40-43个周期(见下文为什么不总是43)。这些光栅线被称为“坏线”。在坏线路上,因此只有20-23个周期可用,而不是63个。
(To更准确地说,当$D011的3个最低位等于$D012的3个最低位时,就会出现坏行(并且我们不在边框中,屏幕也没有被$D011的位4“关闭”)
VIC-chip使用这43个周期中的最后40个周期来读取要显示在文本行上的40个字符。CPU在这40个周期内不能执行任何指令。
然而,在这43个周期的前3个周期中,CPU实际上可以执行其指令的“写入周期”-但仅是写入周期,而不是读取周期。(参见[2])因此,如果您正确计算操作码的时间,您可以在这3个周期中执行指令的某些周期。(注意:唯一有3个写周期的指令是“brk”,它通常是无用的,所以在实践中,你最多只能使用这3个周期中的2个来做一些有用的事情)。
请注意,除了窃取坏线上的周期外,维克还将从具有子画面的光栅线上的CPU窃取周期。

**[2]:**参见“64 doc”,了解C64不同指令的哪些周期是写周期:http://vice-emu.sourceforge.net/plain/64doc.txt

(在表中,写入周期标记为“W”,读取周期标记为“R”)

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

ssgvzors

ssgvzors2#

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

mpgws1up

mpgws1up3#

你可能想检查一下这个:https://github.com/Zibri/C64_Stable_Raster
HSYNC程序的核心是:

DEC $DC03         ; trigger the light pen
INC $DC03         ; restore port B to input
LDA $D013         ; read the raster X position
STA $2
LSR A
LDA $2
ADC #$00          ; if carry is set this is a 8565 i f it's clear it's a 6569
CMP #$0B          ; this is just sheer magic :D
ADC #$11          ; this is just sheer magic :D
LSR A
LSR A
STA SS+1          ; A will be: 0-6
SS:
BVC *
; the following 1 cycle clock slide does not affect any registers nor the cpu status.

.BYTE $80
.BYTE $80, $80
.BYTE $80, $80
.BYTE $44,$5A
RTS  ; Here we we always be at cycle 52 of a scanline.
0ve6wy6x

0ve6wy6x4#

如果我没记错的话(20多年前)。
由于轻微的中断抖动,不太可能获得光栅效果的完全稳定的时序;所以不管你在软件中做什么,你都会在扫描线的开始处有一个“ Flink ”的点。
要解决这个问题,请使用精灵来隐藏 Flink 点。

相关问题