Search code examples
assemblytasm16-bit

Borland C++ 3.1 and TASM - assembler undefined symbol error


I am doing some retro 16bit computing using Borland C++ 3.1 (and TASM) in Dosbox.

I am reading a book by Christopher Lampton - Gardens of Imagination (1994) - and I lost the floppy disk that came with the book.

Which means that I have to write code off of pages.
Has been a smooth ride so far.

Now, I am going to add optimization to my little raycaster, and I added fixmul, fixdiv and drawwall and it all worked fine.

All hell broke lose upon adding the drawfloorrow function.. :(

TASM complains that width, lightindex, xincrement, etc are undefined symbols.
That's odd, because with my extremely limited assembly knowledge: am I not defining them as symbols?

I am confused.

And I know next to nothing about assembly, so if there are a couple of veteran assembly programmers out there that can spot my mistake(s), I would be happy. :)

.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

Errors start to appear with this code:

mov     [width],bx

Disclaimer: Someone in the comments said that I do not know what a symbol is. Of course I do. :)
I just don't know how to create them in assembly.
I create symbols all the time in C and C++, and other languages.

EDIT:

Could it be that the ASM source code file is missing a data segment?

Gist here : OPTI.ASM


Solution

  • This seems to be a library which has to be linked together with other libraries and the main program. I guess the missing symbols are defined in another module. EXTRN declares an external symbol.

    Add

    EXTRN width:word, rownum:word, colnum:word, xincrement:dword, yincrement:dword, texture:dword, textureptr:dword, lightindex:dword, botptr:dword
    

    to the beginning of the source code and you get no more errors. Then you have to find out where the symbols reside.