Commodore 64第1行平滑滚动异常:中断配置导致画面跳变问询
C64水平滚动中断跳变问题排查与解决方案
看起来你遇到了Commodore 64光栅中断配合硬件滚动时的经典同步问题——中断时机不对导致的滚动跳变。让我们一步步拆解问题根源,然后给出精准的修复方案。
核心问题:中断时机与视频扫描不同步
你尝试将滚动开启中断设为光栅行#0、关闭中断设为行#58,这两个选择都踩了C64视频硬件的坑:
- 光栅行#0是顶部边框区域:此时视频芯片还未开始扫描可见文本行,提前设置滚动位不仅不会作用于目标行(屏幕第1行),还可能导致前面的边框/文本行意外滚动;更关键的是,CPU在这个阶段可能还有初始化残留操作,中断响应延迟会导致滚动位在文本行开始扫描后才生效,引发跳变。
- 光栅行#58是文本行的起始边界:C64的每个文本行对应8个连续光栅行(PAL系统中,屏幕第1行对应光栅行58-65)。如果在文本行的起始行触发关闭滚动的中断,视频芯片已经开始扫描该行,此时切换
$d016的滚动位会立即影响当前扫描的像素,导致半个字符的跳变——因为硬件滚动是按像素级实时生效的,必须在整个字符行扫描完成后再切换。
当前代码能运行的原因
你当前设置的滚动开启中断在#50、关闭在#66,这两个行正好覆盖了屏幕第0文本行的完整光栅范围(50-57),且关闭中断在第1文本行结束后(66)。这种设置下,滚动位的切换都发生在文本行的边界/边框区域,视频芯片不会在扫描字符行时看到滚动位变化,所以没有跳变,但代价是滚动区域过大。
解决方案:精准对齐文本行的光栅边界
要实现仅屏幕第1行的平滑滚动,你需要:
- 确定目标文本行的光栅行范围:以PAL系统为例,屏幕第1行(对应内存
$0428-$044F)的光栅行是58-65(每个文本行占8行)。 - 将开启滚动的中断设在目标行的前一行:比如光栅行#57,这样CPU有足够时间在视频芯片开始扫描目标行前完成滚动位设置。
- 将关闭滚动的中断设在目标行的后一行:比如光栅行#66,此时视频芯片已经扫描完目标行,切换滚动位不会影响显示。
修改后的代码示例
以下是调整中断时机后的代码,仅滚动屏幕第1行:
*=$c000 sei lda #$7f sta $dc0d ; 禁用CIAs中断 sta $dd0d and $d011 ; 确保光栅行第9位为0(我们用的行都<256) sta $d011 ldy #57 ; 中断触发在屏幕第1行的前一个光栅行 sty $d012 lda #<scroller ldx #>scroller sta $0314 ; 设置光栅中断向量 stx $0315 lda #$01 sta $d01a ; 启用光栅中断 cli rts noScroller lda $d016 and #$f8 ; 关闭水平滚动(低3位置0) sta $d016 ldy #57 ; 下一次中断回到目标行前一行 sty $d012 lda #<scroller ldx #>scroller sta $0314 stx $0315 inc $d019 ; 清除中断标志 jmp $ea31 ; 回到系统中断处理 scroller lda $d016 and #$f8 adc offset ; 应用当前滚动偏移(0-7) sta $d016 dec offset bpl continue lda #07 sta offset ; 滚动文本行(现在针对屏幕第1行,内存$0428开始) shiftrow ldx #$00 lda $0429,x sta $0428,x inx cpx #39 bne shiftrow+2 fetchnewchar ldx nextchar lda message,x sta $044F ; 第1行的最后一个位置($0428+39) inx lda message,x cmp #255 bne continue-3 ldx #00 stx nextchar continue ldx #66 ; 下一次中断在目标行结束后 stx $d012 lda #<noScroller ldy #>noScroller sta $0314 sty $0315 inc $d019 jmp $ea31 offset byte 07 nextchar byte 00 ; 你的消息字符(保持原内容) message byte 011, 009, 012, 018, 015, 025, 032, 023, 001, 019, 032, 006, 009, 014, 001, 012, 012, 025, 032, 008, 005, 018, 005, 032, 032, 032, 032, 032, 032, 255
关键修改点说明
- 中断触发行从#50改为#57(目标文本行前一行),关闭中断行保持#66(目标文本行后一行)。
- 滚动文本的内存地址从
$0400系列改为$0428系列,对应屏幕第1行。 - 确保滚动位的切换只发生在文本行的边界区域,视频芯片不会在扫描字符时看到滚动位变化,彻底消除跳变。
内容的提问来源于stack exchange,提问作者Nick Developer
相关产品推荐
相关产品推荐

