我在Dosbox中使用Borland C ++ 3.1(和TASM)进行一些复古16位计算。
我正在读一本克里斯托弗兰普顿 - 想象力花园(1994)的书 - 我丢失了随书附带的软盘。
这意味着我必须从页面编写代码 到目前为止一直顺利。
现在,我要为我的小raycaster添加优化,我添加了fixmul
,fixdiv
和drawwall
,这一切都运行良好。
添加drawfloorrow
功能后,所有的一切都输了。:(
TASM抱怨width
,lightindex
,xincrement
等是未定义的符号。
这很奇怪,因为我的装配知识非常有限:我不是把它们定义为符号吗?
我很困惑。
我对组装几乎一无所知,所以如果有几位资深的汇编程序员可以发现我的错误,我会很高兴。 :)
.MODEL large
.CODE
.386
PUBLIC _fixmul,_fixdiv,_drawwall
PUBLIC _drawfloorrow
_fixmul PROC
ARG arg1:DWORD, arg2:DWORD
push bp ; set up BP register
mov bp, sp
mov eax, arg1 ; get first argument into EAX
imul arg2 ; multiply it by second argument
shrd eax,edx,16 ; shift high and low bytes into DX:AX
pop bp
ret
_fixmul ENDP
_fixdiv PROC
ARG numer:DWORD, denom:DWORD
push bp ; set up BP register
mov bp,sp
mov eax,numer ; put dividend into EAX
mov edx,eax ; copy it into EDX
sar edx,16 ; shift high 16 bits of EDX back into EAX
shl eax,16 ; shift low 16 bits of EAX into high 16 bits
idiv denom ; divide by divisor
shld edx,eax,16 ; get result
pop bp
ret
_fixdiv ENDP
COLUMNLOOP MACRO
shld edi,edx,16 ; move integral portion of bitmap
; pointer into DI
mov al,es:[ebx + eax] ; get lightsourced color
mov gs:[si],al ; copy pixel color to screen column
sub edx,ecx ; add increment to bitmap pointer
sub si,bp ; point to next pixel in wall column
ENDM
_drawwall PROC
ARG screenptr:DWORD, bitmapptr:DWORD, height:WORD, increment:DWORD, litelevel:DWORD
push bp ; save BP
mov bp,sp ; set up stack pointer
mov bx,height ; get height in BX
mov ax,200 ; calculate number of pixels to skip
sub ax,bx ; leave result in AX
mov ecx,increment ; get increment in ECX
lgs si,screenptr ; get screen index in GS:SI
lfs di,bitmapptr ; get pointer to bitmap in FS:DI
mov ebx,0 ; clear out EBX
les bx,litelevel ; get lightsource table addr in BX
mov dx,di ; copy increment in DX
shl edx,16 ; reverse the bytes
imul ax,21 ; calculate jump address
mov di,offset walloop ; add start of loop....
add di,ax ; ...to offset in loop
mov bp,320 ; store constant in BP
xor eax,eax ; clear out EAX
jmp di ; jump unto unrolled loop
walloop:
REPT 200 ; repeat macro 200 times
COLUMNLOOP
ENDM
pop bp ; restore BP
ret
_drawwall ENDP
FLOORLOOP MACRO REP
LOCAL SKIPPIXEL
lgs bx,[botptr] ; get pointer to BOTS array
mov al,gs:[bx] ; get current bottom position
mov bx,[rownum] ; get current row number
cmp al,bl ; compare the two
ja SKIPPIXEL ; jump if floor pixel behind the wall
shld edi,edx,10 ; (int)x / 64
shld ebx,ecx,10 ; (int)y / 64
and ebx,15 ; clear out junk in EBX
shl ebx,4 ; multiply y * 16
and edi,15 ; clear out junk in EDI
add bx,di ; BX = (int)y / 64 * 16 + (int)x / 64
mov al,es:[ebp + ebx] ; get tile number in AL
lgs bx,[texture] ; point GS:BX at texture list
mov edi,gs:[ebx + (eax * 4)] ; get pointer to texture map
mov [textureptr],edi ; save texturemap pointer
shld edi,ecx,16 ; calculate (int)y % 64 * 320 + x % 64
shld ebx,edx,16
and edi,63
and ebx,63
imul di,320
add di,bx
lgs bx,[textureptr] ; get pointer to texture
mov al,gs:[bx + di] ; get pixel color
lgs bx,[lightIndex] ; point to lightsource table
mov al,gs:[ebx + eax] ; get lightsourced color
mov fs:[si + rep],al ; put it on screen
SKIPPIXEL:
add dword ptr [botptr],1 ; advance bottom pointer
add ecx,[yincrement] ; add increments to get
add edx,[xincrement] ; next pixel coordinate
ENDM
_drawfloorrow PROC
ARG row:WORD,screenptr:DWORD,texturelist:DWORD,floormap:DWORD,litelevel:DWORD,bots:DWORD,xinc:DWORD,yinc:DWORD,x:DWORD,y:DWORD,w:WORD
push bp ; save BP
mov bp,sp ; set up stack pointer
mov bx,w ; move parameters into memory variables
mov [width],bx
mov ebx,litelevel
mov [lightindex],ebx
mov bx,row
mov [rownum],bx
mov [colnum],0
mov ecx,y
mov edx,x
lfs si,screenptr
mov ebx,xinc
mov [xincrement],ebx
mov ebx,texturelist
mov [texture],ebx
mov ebx,bots
mov [botptr],ebx
les bp,floormap
xor eax,eax ; clear the EAX register
floor:
FLOORLOOP 0 ; unroll FLOORLOOP 8 times
FLOORLOOP 1
FLOORLOOP 2
FLOORLOOP 3
FLOORLOOP 4
FLOORLOOP 5
FLOORLOOP 6
FLOORLOOP 7
add si,8 ; advance screen pointers
add [colnum],8 ; increase column count
mov bx,[colnum] ; have we covered entire viewport?
cmp bx,[width]
jb floor ; if not, do it again
pop bp ; else return to caller
ret
_drawfloorrow ENDP
END
此代码开始显示错误:
mov [width],bx
免责声明:评论中有人说我不知道符号是什么。我当然是了。 :)
我只是不知道如何在装配中创建它们
我一直用C和C ++以及其他语言创建符号。
编辑:
可能是ASM源代码文件缺少数据段吗?
请点击此处:OPTI.ASM
答案 0 :(得分:2)
问题是ASM源文件需要一个DATA段,所以 - 在 RossRidge 和 rkhb 的帮助下 - 这里是文件顶部的摘录缺少数据部分:
.MODEL large
.DATA
yincrement dd 0
.DATA?
wwidth dw ?
lightindex dd ?
rownum dw ?
colnum dw ?
xincrement dd ?
texture dd ?
botptr dd ?
textureptr dd ?
.CODE
.386
PUBLIC _fixmul,_fixdiv,_drawwall
PUBLIC _drawfloorrow
_fixmul PROC
ARG arg1:DWORD, arg2:DWORD
[...]
答案 1 :(得分:1)
这似乎是一个必须与其他库和主程序链接在一起的库。我想丢失的符号是在另一个模块中定义的。 EXTRN声明一个外部符号。
添加
EXTRN width:word, rownum:word, colnum:word, xincrement:dword, yincrement:dword, texture:dword, textureptr:dword, lightindex:dword, botptr:dword
到源代码的开头,你不会再遇到错误。然后你必须找出符号所在的位置。