额外的段不会在程序集中注册颜色数据
Extra segment won't register color data in assembly
我正在编写一个类似于程序集突破的游戏(工具:DosBOX、记事本++、tasm),在图形模式下创建边框和平台时,我偶然发现了 2 个问题:
- 似乎额外的段不会记录颜色信息,因为我无法正确使用它,当我尝试拉它时,它给了我一个黑色的 0,而不是白色的 0Fh .
- 这是我试图解决的一个小问题,但由于某种原因,当我尝试绘制第二个和第三个边框时,第一个边框的一部分变黑了,如果你 运行 代码。我无法确定它发生的原因并且调试器没有显示任何异常。
这是我目前的代码,涉及创建边框、平台和平台移动的主要程序是BorderPaint
、PlatBuild
和PlatMove
IDEAL
MODEL small
STACK 100h
DATASEG
platLoc dw 63806
speed1 dw 10
speed2 dw 0FFFFh
CODESEG
;procedure to paint borders-6 px white pixels
proc BorderPaint
push ax
push bx
push di
push cx
mov ax,0A000h ;accesses graphics mode video memory
mov es,ax
xor di,di
;first line-left vertical
;sets color white
mov ax,0Fh
mov cx,200 ;enters nested loop
FirstLoop1:
push cx
mov cx,6
SecondLoop1:
mov [es:di],ax
inc di
loop SecondLoop1
sub di,6
add di,320
pop cx
loop FirstLoop1
;second line- up horizontal
mov di,7
mov cx,313
FirstLoop2:
push cx
mov cx,6
SecondLoop2:
mov [es:di],ax
add di,320
loop SecondLoop2
sub di,1920
inc di
pop cx
loop FirstLoop2
mov di,314
mov cx,200
FirstLoop3:
push cx
mov cx,6
SecondLoop3:
mov [es:di],ax
inc di
loop SecondLoop3
sub di,6
add di,320
pop cx
loop FirstLoop3
; xor di,di
; mov ax,0Fh
; mov cx,200
; FirstLoop4:
; push cx
; mov cx,6
; SecondLoop4:
; mov [es:di],ax
; inc di
; loop SecondLoop4
; sub di,6
; add di,320
; pop cx
; loop FirstLoop4
pop cx
pop di
pop bx
pop ax
ret
endp BorderPaint
proc PlatBuild
push di
push cx
push ax
mov di,[platLoc]
mov ax,5
mov cx,40
LoopPaint2:
push cx
mov cx,10
LoopPaint1:
mov [es:di],ax
sub di,320
loop LoopPaint1
add di,320*10
inc di
pop cx
loop LoopPaint2
pop ax
pop cx
pop di
ret
endp PlatBuild
Proc PlatErase
push di
push cx
push ax
mov di,[platLoc]
mov ax,0
mov cx,40
LoopPaint4:
push cx
mov cx,10
LoopPaint3:
mov [es:di],ax
sub di,320
loop LoopPaint3
add di,320*10
inc di
pop cx
loop LoopPaint4
pop ax
pop cx
pop di
ret
endp PlatErase
Proc PlatMove
push ax
push cx
push dx
push di
mov ax,0A000h
mov es,ax
call BorderPaint
;Input
CheckPress1:
mov ah,0h
int 16h
cmp al,'a'
jne nxt11
jmp MoveLeft1
Nxt11:
cmp al,'d'
jne nxt12
jmp MoveRight1
Nxt12:
cmp al,'q'
jne CheckPress1
jmp endproc1
MoveLeft1:
call Delay
mov dx,[platLoc]
add dx,8*320
sub dx,1d
mov di,dx
mov ax,[es:di]
cmp ax,0Fh
jne move1
jmp CheckPress1
move1:
call PlatErase
dec [platLoc]
call PlatBuild
mov ah,1h
int 16h
je MoveLeft1
jmp CheckPress1
MoveRight1:
call Delay
mov dx,[platLoc]
add dx,41
mov di,dx
mov ax,[es:di]
cmp ax,0Fh
jne move2
jmp CheckPress1
move2:
call PlatErase
inc [platLoc]
call PlatBuild
mov ah,1h
int 16h
je MoveRight1
jmp CheckPress1
EndProc1:
pop di
pop dx
pop cx
pop ax
ret
endp PlatMove
proc Delay
push cx
mov cx, [speed2]
LoopLong:
push cx
mov cx, [speed1]
LoopShort:
loop LoopShort
pop cx
loop LoopLong
pop cx
ret
Endp Delay
start:
mov ax,@data
mov ds,ax
mov ax,13h
int 10h
call BorderPaint
call PlatBuild
mov ax, [es:63680]
call PlatMove
exit:
mov ax,4c00h
int 21h
END startenter code here
mov [es:di],ax
将 WORD(两个字节)写入 VRAM,ax = 0x000F
,因此您写入 [es:di]
值 0x0F
,并在 [es:di+1]
值 0x00
(黑色).
sub di,6
add di,320
这是亵渎 :/ ... add di,320-6
意图在源级别上仍然可见,但也显示出对机器的无知程度降低,从而最大限度地减少了使用的指令量。
顺便说一句,如果你想存储 6 个字节的 0x0F 值,你也可以存储三个字的 0x0F0F 值,节省一半的 VRAM 访问(这是昂贵的)。那么
mov di,<some VRAM address>
mov cx,<number of lines>
mov ax,0F0Fh ; <color><color> (two pixels at same time)
Draw6PixelsLoop:
mov [es:di],ax
mov [es:di+2],ax
mov [es:di+4],ax
add di,320
dec cx
jnz Draw6PixelsLoop
是如何绘制 6 个像素(仅写入 3 个 VRAM)并在下方移动 1 行的更优化的硬编码方式。
- 不确定你的意思,但可能有一个问题是从
PlatMove
中的 VRAM 中读取字(两个像素),然后将它们与 0Fh cmp ax,0Fh
进行比较,即两个像素 "white + black" = 000Fh
。所以在左侧这可能会很好地工作,但在右侧它只会在边界的末端找到这样的两个像素(记住在右侧的最后一个像素之后下一个字节是第一个左边的像素下一行,所以如果你有 6 个像素的边框,第一个白色+黑色像素在左边框结束的下一行。
读写问题
由于您的程序使用 320x200 256 色视频模式 13h,每个像素都由 VRAM 中的一个字节表示。你的代码中最重要的问题,Ped7g 已经指出了这一点,是你一直在读写 words 而你应该读写 bytes .
我将通过对顶部边界进行更正来说明我们的意思。 不要忘记在其他地方进行类似的更改!
;second line- up horizontal
mov di,6 ; (6,0) <--- See 1.
mov cx,320-6-6 ; Width <--- See 2.
FirstLoop2:
push cx
mov cx,6 ; Height
SecondLoop2:
mov [es:di],al ; Color 0Fh, Byte from AL instead of word from AX
add di,320 ; Go down 1 line
loop SecondLoop2
sub di,320*6 ; Take back 6 additions of 320
inc di ; Go right 1 pixel
pop cx
loop FirstLoop2
我选择这部分是因为它还有一些额外的错误:
- 鉴于左侧边框为 6 像素宽,上边框从像素位置 6 开始(xy 位置从零开始)。
- 鉴于稍后您还将绘制一个 6 像素宽的右侧边框,您只需绘制中间的部分:320-6-6
上面的代码可以进行很多优化,但目前您正在努力使事情正常进行。所以请不要尝试一次处理超过 1 个像素。编程中的一个重要格言是:"First make it work, then make it better".
也像我写的那样写评论。它将有助于理解您在做什么。
试色问题
MoveLeft1:
call Delay
mov dx,[platLoc]
add dx,8*320 ???
sub dx,1d
mov di,dx
mov ax,[es:di] ???
cmp ax,0Fh ???
在 MoveLeft1 代码中,您从错误计算的地址读取!通过将 8*320 添加到 dx
寄存器,您可以在屏幕 下方 下登陆,因此在屏幕外。实际上,由于段环绕,您将错误地寻址 VRAM 顶部的一些随机像素。
MoveLeft1:
call Delay
mov di, [platLoc]
mov al, [es:di-1] ; Pixel to the left of the platform
cmp al, 0Fh ; Is it white?
jne move1
jmp CheckPress1
move1:
call PlatErase
dec [platLoc]
call PlatBuild
mov ah, 01h
int 16h ; Key pending?
je MoveLeft1
jmp CheckPress1
MoveRight1:
call Delay
mov dx,[platLoc]
add dx,41 ???
mov di,dx
mov ax,[es:di] ???
cmp ax,0Fh ???
在 MoveRight1 代码中,您还读取了错误的地址。平台宽度为 40 像素,因此最后一个像素位于 platLoc + 39,因此需要检查的像素位于 platLoc + 40 .
MoveRight1:
call Delay
mov di, [platLoc]
mov al, [es:di+40] ; Pixel to the right of the platform
cmp al, 0Fh ; Is it white?
jne move2
jmp CheckPress1
move2:
call PlatErase
inc [platLoc]
call PlatBuild
mov ah, 01h
int 16h ; Key pending?
je MoveRight1
jmp CheckPress1
我正在编写一个类似于程序集突破的游戏(工具:DosBOX、记事本++、tasm),在图形模式下创建边框和平台时,我偶然发现了 2 个问题:
- 似乎额外的段不会记录颜色信息,因为我无法正确使用它,当我尝试拉它时,它给了我一个黑色的 0,而不是白色的 0Fh .
- 这是我试图解决的一个小问题,但由于某种原因,当我尝试绘制第二个和第三个边框时,第一个边框的一部分变黑了,如果你 运行 代码。我无法确定它发生的原因并且调试器没有显示任何异常。
这是我目前的代码,涉及创建边框、平台和平台移动的主要程序是BorderPaint
、PlatBuild
和PlatMove
IDEAL
MODEL small
STACK 100h
DATASEG
platLoc dw 63806
speed1 dw 10
speed2 dw 0FFFFh
CODESEG
;procedure to paint borders-6 px white pixels
proc BorderPaint
push ax
push bx
push di
push cx
mov ax,0A000h ;accesses graphics mode video memory
mov es,ax
xor di,di
;first line-left vertical
;sets color white
mov ax,0Fh
mov cx,200 ;enters nested loop
FirstLoop1:
push cx
mov cx,6
SecondLoop1:
mov [es:di],ax
inc di
loop SecondLoop1
sub di,6
add di,320
pop cx
loop FirstLoop1
;second line- up horizontal
mov di,7
mov cx,313
FirstLoop2:
push cx
mov cx,6
SecondLoop2:
mov [es:di],ax
add di,320
loop SecondLoop2
sub di,1920
inc di
pop cx
loop FirstLoop2
mov di,314
mov cx,200
FirstLoop3:
push cx
mov cx,6
SecondLoop3:
mov [es:di],ax
inc di
loop SecondLoop3
sub di,6
add di,320
pop cx
loop FirstLoop3
; xor di,di
; mov ax,0Fh
; mov cx,200
; FirstLoop4:
; push cx
; mov cx,6
; SecondLoop4:
; mov [es:di],ax
; inc di
; loop SecondLoop4
; sub di,6
; add di,320
; pop cx
; loop FirstLoop4
pop cx
pop di
pop bx
pop ax
ret
endp BorderPaint
proc PlatBuild
push di
push cx
push ax
mov di,[platLoc]
mov ax,5
mov cx,40
LoopPaint2:
push cx
mov cx,10
LoopPaint1:
mov [es:di],ax
sub di,320
loop LoopPaint1
add di,320*10
inc di
pop cx
loop LoopPaint2
pop ax
pop cx
pop di
ret
endp PlatBuild
Proc PlatErase
push di
push cx
push ax
mov di,[platLoc]
mov ax,0
mov cx,40
LoopPaint4:
push cx
mov cx,10
LoopPaint3:
mov [es:di],ax
sub di,320
loop LoopPaint3
add di,320*10
inc di
pop cx
loop LoopPaint4
pop ax
pop cx
pop di
ret
endp PlatErase
Proc PlatMove
push ax
push cx
push dx
push di
mov ax,0A000h
mov es,ax
call BorderPaint
;Input
CheckPress1:
mov ah,0h
int 16h
cmp al,'a'
jne nxt11
jmp MoveLeft1
Nxt11:
cmp al,'d'
jne nxt12
jmp MoveRight1
Nxt12:
cmp al,'q'
jne CheckPress1
jmp endproc1
MoveLeft1:
call Delay
mov dx,[platLoc]
add dx,8*320
sub dx,1d
mov di,dx
mov ax,[es:di]
cmp ax,0Fh
jne move1
jmp CheckPress1
move1:
call PlatErase
dec [platLoc]
call PlatBuild
mov ah,1h
int 16h
je MoveLeft1
jmp CheckPress1
MoveRight1:
call Delay
mov dx,[platLoc]
add dx,41
mov di,dx
mov ax,[es:di]
cmp ax,0Fh
jne move2
jmp CheckPress1
move2:
call PlatErase
inc [platLoc]
call PlatBuild
mov ah,1h
int 16h
je MoveRight1
jmp CheckPress1
EndProc1:
pop di
pop dx
pop cx
pop ax
ret
endp PlatMove
proc Delay
push cx
mov cx, [speed2]
LoopLong:
push cx
mov cx, [speed1]
LoopShort:
loop LoopShort
pop cx
loop LoopLong
pop cx
ret
Endp Delay
start:
mov ax,@data
mov ds,ax
mov ax,13h
int 10h
call BorderPaint
call PlatBuild
mov ax, [es:63680]
call PlatMove
exit:
mov ax,4c00h
int 21h
END startenter code here
mov [es:di],ax
将 WORD(两个字节)写入 VRAM,ax = 0x000F
,因此您写入[es:di]
值0x0F
,并在[es:di+1]
值0x00
(黑色).
sub di,6
add di,320
这是亵渎 :/ ... add di,320-6
意图在源级别上仍然可见,但也显示出对机器的无知程度降低,从而最大限度地减少了使用的指令量。
顺便说一句,如果你想存储 6 个字节的 0x0F 值,你也可以存储三个字的 0x0F0F 值,节省一半的 VRAM 访问(这是昂贵的)。那么
mov di,<some VRAM address>
mov cx,<number of lines>
mov ax,0F0Fh ; <color><color> (two pixels at same time)
Draw6PixelsLoop:
mov [es:di],ax
mov [es:di+2],ax
mov [es:di+4],ax
add di,320
dec cx
jnz Draw6PixelsLoop
是如何绘制 6 个像素(仅写入 3 个 VRAM)并在下方移动 1 行的更优化的硬编码方式。
- 不确定你的意思,但可能有一个问题是从
PlatMove
中的 VRAM 中读取字(两个像素),然后将它们与 0Fhcmp ax,0Fh
进行比较,即两个像素 "white + black" =000Fh
。所以在左侧这可能会很好地工作,但在右侧它只会在边界的末端找到这样的两个像素(记住在右侧的最后一个像素之后下一个字节是第一个左边的像素下一行,所以如果你有 6 个像素的边框,第一个白色+黑色像素在左边框结束的下一行。
读写问题
由于您的程序使用 320x200 256 色视频模式 13h,每个像素都由 VRAM 中的一个字节表示。你的代码中最重要的问题,Ped7g 已经指出了这一点,是你一直在读写 words 而你应该读写 bytes .
我将通过对顶部边界进行更正来说明我们的意思。 不要忘记在其他地方进行类似的更改!
;second line- up horizontal
mov di,6 ; (6,0) <--- See 1.
mov cx,320-6-6 ; Width <--- See 2.
FirstLoop2:
push cx
mov cx,6 ; Height
SecondLoop2:
mov [es:di],al ; Color 0Fh, Byte from AL instead of word from AX
add di,320 ; Go down 1 line
loop SecondLoop2
sub di,320*6 ; Take back 6 additions of 320
inc di ; Go right 1 pixel
pop cx
loop FirstLoop2
我选择这部分是因为它还有一些额外的错误:
- 鉴于左侧边框为 6 像素宽,上边框从像素位置 6 开始(xy 位置从零开始)。
- 鉴于稍后您还将绘制一个 6 像素宽的右侧边框,您只需绘制中间的部分:320-6-6
上面的代码可以进行很多优化,但目前您正在努力使事情正常进行。所以请不要尝试一次处理超过 1 个像素。编程中的一个重要格言是:"First make it work, then make it better".
也像我写的那样写评论。它将有助于理解您在做什么。
试色问题
MoveLeft1: call Delay mov dx,[platLoc] add dx,8*320 ??? sub dx,1d mov di,dx mov ax,[es:di] ??? cmp ax,0Fh ???
在 MoveLeft1 代码中,您从错误计算的地址读取!通过将 8*320 添加到 dx
寄存器,您可以在屏幕 下方 下登陆,因此在屏幕外。实际上,由于段环绕,您将错误地寻址 VRAM 顶部的一些随机像素。
MoveLeft1:
call Delay
mov di, [platLoc]
mov al, [es:di-1] ; Pixel to the left of the platform
cmp al, 0Fh ; Is it white?
jne move1
jmp CheckPress1
move1:
call PlatErase
dec [platLoc]
call PlatBuild
mov ah, 01h
int 16h ; Key pending?
je MoveLeft1
jmp CheckPress1
MoveRight1: call Delay mov dx,[platLoc] add dx,41 ??? mov di,dx mov ax,[es:di] ??? cmp ax,0Fh ???
在 MoveRight1 代码中,您还读取了错误的地址。平台宽度为 40 像素,因此最后一个像素位于 platLoc + 39,因此需要检查的像素位于 platLoc + 40 .
MoveRight1:
call Delay
mov di, [platLoc]
mov al, [es:di+40] ; Pixel to the right of the platform
cmp al, 0Fh ; Is it white?
jne move2
jmp CheckPress1
move2:
call PlatErase
inc [platLoc]
call PlatBuild
mov ah, 01h
int 16h ; Key pending?
je MoveRight1
jmp CheckPress1