[英]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.