Amstrad CPC模拟器(WinApe)中Gameboy Logo演示出现异常杂色像素
Amstrad CPC模式1下Gameboy Logo动画杂色问题修复
问题描述
用Z80汇编在Amstrad CPC模拟器WinApe的视频模式1中制作Gameboy Logo演示,单独绘制Logo显示正常,但添加绘制-擦除循环动画后,出现未绘制过的杂色像素,Logo最后一行本该只有红色,却混入其他颜色。
问题截图

原代码
;; testlogo.asm ;; .cls equ &BC14 ;; Clear screen org &4000 run &4000 ;; call cls ld hl, #c020 ;; initial position of video ld a,#05 ;; times logo down call loop1 ;; call main loop jr $ ;; loop1: ld bc,logo ;; initial position of logo ;; bc remains until logo ;; is fully painted ld e,#08 call loop_paint ld de, #c050 add hl,de ;; the second 8 row group pixels ld e,#08 call loop_paint ld de,#c050 add hl,de ;; wait until 'down' logo ld b,#cc call wait ld de, #ff60 ;; recover hl position ;; to 'erase' upward logo add hl,de ld e,#08 call loop_erase1 ;; call to 'erase' pixels ;; from logo ;; (it could be optimized in one calling) ld de, #c050 add hl,de ld e,#08 call loop_erase1 ld de, #c050 add hl,de dec a jr nz, loop1 ret ;; loop_paint: ld d,#0b call loop_logo ;; call to paint logo push bc ;; save bc in stack ;; for using adding in bc ld bc,#07f5 ;; 800 for next row (minus) 0b last column add hl,bc pop bc dec e jr nz, loop_paint ret ;; loop_logo: ;; finally 'paints' logo ;; in memory video push af ;; save 'a' register ;; because is used ;; as counter in main loop ld a, (bc) ld (hl), a pop af inc l inc c dec d jr nz,loop_logo ret ;; loop_erase1: ;; row by row in mode 1 video ld d,#0b call loop_erase2 ld bc,#07f5 ;;800 next row - 0b last column add hl,bc dec e jr nz,loop_erase1 ret ;; loop_erase2: ;; column by column in mode 1 video ld (hl), #00 inc l dec d jr nz,loop_erase2 ret ;; logo: db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00 db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00 db #00, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #88, #00 db #33, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #EE, #00 db #33, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #E6, #00 db #FC, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #F1, #88 db #FD, #F5, #FB, #F5, #FE, #FF, #F3, #F3, #FB, #FD, #88 db #FD, #F9, #FB, #FD, #F0, #F8, #F4, #FA, #F1, #F1, #88 db #FD, #F1, #FA, #FD, #F6, #FF, #F4, #FB, #F9, #F1, #88 db #FD, #F9, #FA, #F5, #F2, #F1, #F4, #FA, #F1, #F1, #88 db #FD, #F5, #FA, #F5, #FE, #FF, #F3, #F2, #F1, #F1, #88 db #FC, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #F1, #88 db #33, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #E6, #00 db #33, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #EE, #00 db #00, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #88, #00 db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00 ret ;; wait: halt dec b jr nz,wait ret
问题根源
- 换行偏移计算错误:Amstrad CPC模式1每行占80字节(0x50),绘制11字节(0xB)后,下一行起始地址需偏移
0x50 - 0xB = 0x45,原代码错误使用0x07f5,导致绘制行偏离到视频内存错误区域,擦除时无法覆盖这些区域,残留杂色。 - 擦除阶段HL位置恢复错误:手动计算偏移易出错,导致擦除区域与绘制区域不匹配。
修复后的代码
;; testlogo_fixed.asm ;; .cls equ &BC14 ;; Clear screen org &4000 run &4000 ;; call cls ld hl, #c020 ;; initial position of video ld a,#05 ;; times logo down call loop1 ;; call main loop jr $ ;; loop1: push hl ;; 保存初始视频位置,擦除时恢复 ld bc,logo ;; initial position of logo ld e,#08 call loop_paint ld de, #c050 add hl,de ;; the second 8 row group pixels ld e,#08 call loop_paint ld de,#c050 add hl,de ;; wait until 'down' logo ld b,#cc call wait pop hl ;; 恢复初始视频位置,确保擦除区域正确 ld e,#08 call loop_erase1 ;; call to 'erase' pixels ld de, #c050 add hl,de ld e,#08 call loop_erase1 ld de, #c050 add hl,de dec a jr nz, loop1 ret ;; loop_paint: ld d,#0b call loop_logo ;; call to paint logo push bc ;; save bc in stack ld bc,#0045 ;; 模式1每行80字节(0x50),减去已绘制的11字节(0xB),得到下一行偏移 add hl,bc pop bc dec e jr nz, loop_paint ret ;; loop_logo: ;; finally 'paints' logo ;; in memory video push af ;; save 'a' register ld a, (bc) ld (hl), a pop af inc l inc c dec d jr nz,loop_logo ret ;; loop_erase1: ;; row by row in mode 1 video ld d,#0b call loop_erase2 ld bc,#0045 ;; 同绘制阶段的换行偏移 add hl,bc dec e jr nz,loop_erase1 ret ;; loop_erase2: ;; column by column in mode 1 video ld (hl), #00 inc l dec d jr nz,loop_erase2 ret ;; logo: db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00 db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00 db #00, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #88, #00 db #33, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #EE, #00 db #33, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #E6, #00 db #FC, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #F1, #88 db #FD, #F5, #FB, #F5, #FE, #FF, #F3, #F3, #FB, #FD, #88 db #FD, #F9, #FB, #FD, #F0, #F8, #F4, #FA, #F1, #F1, #88 db #FD, #F1, #FA, #FD, #F6, #FF, #F4, #FB, #F9, #F1, #88 db #FD, #F9, #FA, #F5, #F2, #F1, #F4, #FA, #F1, #F1, #88 db #FD, #F5, #FA, #F5, #FE, #FF, #F3, #F2, #F1, #F1, #88 db #FC, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #F1, #88 db #33, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #F0, #E6, #00 db #33, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #EE, #00 db #00, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #FF, #88, #00 db #00, #00, #00, #00, #00, #00, #00, #00, #00, #00, #00 ret ;; wait: halt dec b jr nz,wait ret
修复说明
- 将
loop_paint和loop_erase1中的换行偏移0x07f5改为0x0045,匹配模式1的视频内存行布局。 - 在
loop1中用push hl/pop hl保存和恢复初始绘制位置,确保擦除区域与绘制区域完全对应,避免手动计算偏移的错误。
内容的提问来源于stack exchange,提问作者reymagnus
相关产品推荐
相关产品推荐

