【问题标题】:ASM x86 How to get the pointer from an array properly? (16-bit TASM / DOS)ASM x86 如何正确地从数组中获取指针? (16 位 TASM/DOS)
【发布时间】:2015-12-21 08:00:33
【问题描述】:

好吧,希望这是一个简单的问题:我需要访问一个数组以在 16 位 TASM 中实现双缓冲(我使用模式 13h)。但是:无论我使用“OFFSET”、“BYTE PTR [Array]”、“BYTE PTR Array”还是我已经尝试过的任何方法,程序都会读取/写入不正确的内存块,这部分是在实际启动之后数组。

这是我的(目前还没有真正优化且非常混乱)代码:

.MODEL  MEDIUM
.STACK
.DATA
        XPos    DW      0
        YPos    DB      0
        Color   DB      0

        BoxX1   DW      0
        BoxY1   DB      0
        BoxX2   DW      0
        BoxY2   DB      0

        VPage   DB      64010   DUP(0)  ;TODO: Size *might* be incorrect.
        PageSeg DW      0
.CODE

SetVGA13 PROC
        MOV     AX,     0013h   ;Screen mode 13.
        INT     10h             ;Set screen mode to AX.
        MOV     AX,     0A000h  ;Screen segment.
        MOV     ES,     AX      ;You can't affect segment registers
        RET
ENDP

;-------DrawPixel---------------
; WORD XPos  = x
; WORD YPos  = y
; BYTE Color = colour
;-------------------------------
DrawPixel PROC
        XOR     AH,     AH
        MOV     AL,     [YPos]
        MOV     DX,     320
        MUL     DX
        ADD     AX,     [XPos]
        MOV     DI,     AX
        MOV     AL,     [Color]
        MOV     ES,     [PageSeg]  
        ;ADD     ES,     DI
        MOV     ES:[DI],AL
        ;MOV     ES:[DI],AL
        RET
ENDP

DrawBox PROC
        MOV CL, [BoxY1]
        YLoop:
        MOV     BL,     CL
        PUSH    CX
        MOV     CX,     [BoxX1]
        XLoop:
        MOV     [XPos], CX
        MOV     [YPos], BL
        MOV     [Color],CL
        CALL    DrawPixel
        INC     CX
        CMP     CX,     [BoxX2]
        JNZ     XLoop
        POP     CX
        INC     CL
        CMP     CL,     [BoxY2]
        JNZ     YLoop
        RET
ENDP

WaitFrame PROC
        PUSH    DX
        ; Port #03DA contains VGA status
        MOV     DX,     03DAh
        IN      AL,     DX
        WaitRetrace:
        ; Bit 3 will be on if we're in retrace
        TEST    AL,     08h
        JNZ     WaitRetrace
        EndRefresh:
        IN      AL,     DX
        TEST    AL,     08h
        JZ      EndRefresh
        POP     DX
        RET
ENDP

RestoreVideo PROC
        ; Return to text mode
        MOV     AX,     03h
        INT     10h
        RET
ENDP

ClearScreen PROC
        XOR     CX,     CX
        ;MOV     ES,     [PageSeg] 

        ClearLoop:
        MOV     DI,     CX  
        ;MOV     ES,     [PageSeg]
        MOV     BX,     OFFSET VPage
        ADD     BX,     CX
        MOV     AL,     [BX];VPage[DI];ES:[DI] 
        MOV     [Color],AL 

        MOV     AX,     0A000h
        MOV     ES,     AX
        MOV     AL,     [Color]
        MOV     ES:[DI],AL

        INC     CX
        CMP     CX,     64000
        JNZ     ClearLoop
        RET
ENDP

Main:
        ;INITIALISE
        MOV     BX,     OFFSET VPage
        MOV     [PageSeg],BX


        CALL    SetVGA13
        ;CALL    MakePalette       

        MOV     [BoxX1],33
        MOV     [BoxY1],33
        MOV     [BoxX2],99
        MOV     [BoxY2],99

        ;LOOP
        GameLoop:
        ;DRAW
        ;CALL    DrawBox
        CALL    ClearScreen
        ;CALL    WaitFrame

        ;INPUT
        MOV     DX,     60h
        IN      AL,     DX

        CMP     AL,     75
        JNZ     NotLeft
        SUB     [BoxX1],1
        SUB     [BoxX2],1
        NotLeft:

        IN      AL, DX
        CMP     AL, 77
        JNZ     NotRight
        ADD     [BoxX1],1
        ADD     [BoxX2],1
        NotRight:


        CMP     AL,     1
        JNZ     GameLoop



        ;END PROGRAM
        Error:

        ;CALL    ClearScreen
        CALL    RestoreVideo
        MOV     AH,     4Ch
        INT     21h
        END     Main

这段代码显示了一个彩虹色的盒子,你可以用左右箭头键移动它,

;INITIALISE
        MOV     BX,     OFFSET VPage
        MOV     [PageSeg],BX

这是我获取缓冲区指针的可悲尝试,但没有返回正确的指针

对不起,我的问题没有完成,当我出于某种原因立即起床时,我意识到。

【问题讨论】:

  • 我建议使用调试器(在您的情况下为 Turbo 调试器)单步执行代码以查看发生了什么。
  • 您没有提及您认为是哪个内存地址或数组(甚至是哪个指令)有问题。
  • 我已投票决定关闭这不是 Minimal, Complete, Verifiable example 。没有描述程序做什么、如何工作、预期什么以及发生什么。引用了访问Array 可能出现的问题,但代码中没有这样的变量,也没有表明发布者认为问题出在哪里(特定指令)。一些代码在游戏循环中被注释掉了,我认为这不是一个很好的例子。
  • ds 未正确初始化。
  • @FrankKotler 同样,除了未设置 DS(默认为 PSP)之外,我注意到的是 ES 被设置为VPageoffset,这是完全错误的。发帖者可能希望用类似这样的东西来初始化 DSESPageSeg,而不是 MOV BX, @data,然后是 MOV DS, BX,然后是 MOV [PageSeg],BX

标签: pointers assembly x86 tasm segment


【解决方案1】:

虽然这不是我编写代码的方式,但我会提供一些建议,让您更接近于解决问题。

当您的可执行文件加载 DSES 寄存器最初指向您的程序的DOS PSP。在您的情况下,您至少需要将 DS 指向您的 DATA 段。由 DOS EXE 加载程序在运行时填充的 DATA 段可以在您的代码中通过在段名称前加上 @ (AT) 符号来引用。所以你可以替换这段代码:

;INITIALISE
MOV     BX,     OFFSET VPage
MOV     [PageSeg],BX

有了这个:

;INITIALISE
MOV BX, @DATA           ; Set up DS with our program's DATA segment
MOV DS, BX              
MOV     [PageSeg],BX    ; VPage is in DATA segment, move segment to PageSeg

在您的DrawPixel 代码中,您需要将VPage 偏移量添加到DI。替换此代码:

XOR     AH,     AH
MOV     AL,     [YPos]
MOV     DX,     320
MUL     DX
ADD     AX,     [XPos]
MOV     DI,     AX
MOV     AL,     [Color]
MOV     ES,     [PageSeg]  
MOV     ES:[DI],AL

与:

XOR     AH,     AH
MOV     AL,     [YPos]
MOV     DX,     320
MUL     DX
ADD     AX,     [XPos]
MOV     DI,     AX
MOV     AL,     [Color]
MOV     ES,     [PageSeg]  
ADD     DI,     OFFSET VPage    ; We need to add VPage's offset 
                                ; from beginning of PageSeg
MOV     ES:[DI],AL

视频模式 13h 为 320x200x256 色。所需的视频内存量为 320*200*1 = 64000。这可以从以下位置更改:

VPage   DB      64010   DUP(0)  ;TODO: Size *might* be incorrect. 

到:

VPage   DB      64000   DUP(0)

通过这些更改,程序似乎显示了一个彩虹框,并使用箭头键在屏幕上左右移动。

可能还有其他错误,但我不知道您想要实现什么。这段代码可以大大简化。我的更改是与您编写程序的方式并使其具有一定功能的最小更改。

【讨论】:

  • 谢谢,由于我多次尝试使双缓冲区工作,很多代码确实搞砸了。是的,我知道 64000 是正确的大小,但在此之前大小是 63999 字节。再次感谢您帮助我
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-27
  • 2012-07-01
  • 1970-01-01
  • 2018-03-01
  • 2019-03-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多