Files
CydandClaude Fable 5 fdd9ac9d97 Initial import: Tesla Release 4.10 (Tesla:BattleTech & Tesla:Red Planet)
Archival snapshot of the Virtual World Entertainment Tesla cockpit
software, 1994-1996: MUNGA engine and L4 pod layer source (Borland
C++ 5.0), BT/RP game code, and game content (models, audio, maps,
gauges, Division renderer data). Includes third-party libraries:
Division dVS/DPL graphics, HMI SOS audio, WATTCP networking.

Files are preserved byte-for-byte (.gitattributes disables all
line-ending conversion). README.md documents the layout, target
hardware, and toolchain.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 13:21:58 -05:00

655 lines
22 KiB
NASM

;===========================================================================
; File: L4SVGA16.asm
; Project: MUNGA
; Contents: SVGA 16-bit buffered graphics operations
;---------------------------------------------------------------------------
; Date Who Modification
; -------- --- -----------------------------------------------------------
; 03/08/95 CPB Initial coding (started from VGAbuf8.asm)
;---------------------------------------------------------------------------
; Copyright (C) 1995, Virtual World Entertainment, Inc.
; All Rights reserved worldwide
; This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL
;===========================================================================
include l4asm.inc
include pcdpmi.inc
;===========================================================================
; Equates
;===========================================================================
;--------------------------------------------------------------
; VGA CRTC registers (in color mode: monochrome is different!)
; monochrome is 3B4/3B5 respectively
;--------------------------------------------------------------
CRTC_INDEX equ 03D4h
CRTC_DATA equ 03D5h
CRTC_INDEX_HTOTAL equ 00h
CRTC_INDEX_HDISPENEND equ 01h
CRTC_INDEX_HBSTART equ 02h
CRTC_INDEX_HBEND equ 03h
CRTC_INDEX_HRSTART equ 04h
CRTC_INDEX_HREND equ 05h
CRTC_INDEX_VTOTAL equ 06h
CRTC_INDEX_OVERFLOW equ 07h
CRTC_INDEX_PRSCAN equ 08h
CRTC_INDEX_MAXSCAN equ 09h
CRTC_INDEX_CUR_START equ 0Ah
CRTC_INDEX_CUR_END equ 0Bh
CRTC_INDEX_STARTHIGH equ 0Ch
CRTC_INDEX_STARTLOW equ 0Dh
CRTC_INDEX_CURSORHIGH equ 0Eh
CRTC_INDEX_CURSORLOW equ 0Fh
CRTC_INDEX_VRSTART equ 10h
CRTC_INDEX_VREND equ 11h ;;bit 7=1 to write-protect 0..7
CRTC_INDEX_VDENABEND equ 12h
CRTC_INDEX_OFFSET equ 13h
CRTC_INDEX_UNDERLINE equ 14h
CRTC_INDEX_VBSTART equ 15h
CRTC_INDEX_VBEND equ 16h
CRTC_INDEX_MODECTL equ 17h
CRTC_INDEX_LINECMP equ 18h
;--------------------------------------------------------------
; VGA sequencer registers
;--------------------------------------------------------------
SRX equ 03C4h
SRDATA equ 03C5h
SR0 equ 000h ;reset
SR1 equ 001h ;clocking mode
SR2 equ 002h ;plane mask
SR3 equ 003h ;character map select
SR4 equ 004h ;memory mode
;--------------------------------------------------------------
; VGA graphics controller registers
;--------------------------------------------------------------
GRX equ 03CEh
GRDATA equ 03CFh
GR0 equ 000h ;set/reset
GR1 equ 001h ;set/reset enable
GR2 equ 002h ;color compare
GR3 equ 003h ;data rotate
GR4 equ 004h ;read map select
GR5 equ 005h ;mode
GR6 equ 006h ;miscellaneous
GR7 equ 007h ;color don't care
GR8 equ 008h ;bit mask
;--------------------------------------------------------------
; VGA attribute controller registers
;--------------------------------------------------------------
ARX equ 03C0h ;????
ARDATA equ 03C1h
PEL_WRITE_ADDR equ 03C8h ;write begins "write" operation
PEL_READ_ADDR equ 03C7h ;write begins "read" operation
PEL_STATE equ 03C7h ;read returns DAC state
PEL_DATA equ 03C9h
;--------------------------------------------------------------
; VWE LBE4 video splitter board addresses
;--------------------------------------------------------------
VWE_HC_ON equ 031Ah ;write to this port turns on high-color divider
VWE_HC_OFF equ 0319h ;write to this port turns off high-color divider
;--------------------------------------------------------------
; Video buffer base address
;--------------------------------------------------------------
VIDEO_BUFFER EQU 0000h
VIDEO_SEGMENT EQU 0A000h
BIOS_SEGMENT EQU 0C000h
;===========================================================================
; Macros
;===========================================================================
;===========================================================================
; Structures
;===========================================================================
PixelMap STRUC
pmX dd ?
pmY dd ?
pmPtr dd ?
PixelMap ENDS
BitMap STRUC
bmX dd ?
bmY dd ?
bmWords dd ?
bmPtr dd ?
BitMap ENDS
;===========================================================================
; Data segment
;===========================================================================
BEGIN_DATA
regs DPMIrealModeRegs <>
video_descriptor dw ?
pageFunction dd ? ;THE ORDER OF THESE TWO IS CRITICAL!
BIOS_descriptor dw ? ;(they constitute a far pointer in 32-bits)
bitMapFcn dd ? ;used by Buf16DrawBitMap
tempColor db 256*3 dup ()
;; testWord dw 0
badVideoActive db 0 ;flag indicating deliberately bad video is on
crtc_htotal db ? ;horizontal total
END_DATA
;===========================================================================
; Code segment
;===========================================================================
BEGIN_CODE
;-------------------------------------------------------------------------
; SVGASetMode()
; Set requested VESA display mode
;-------------------------------------------------------------------------
; Enter:
; LWord mode = requested display mode
;-------------------------------------------------------------------------
; Returns:
; (void)
;-------------------------------------------------------------------------
BEGIN_C_PROC SVGASetMode <eax,ebx,ecx,edi,es>
ARG_DWORD sm_mode
ARG_CPTR sm_ptr
BUILD_STACK_FRAME
mov eax,sm_ptr
mov pageFunction,eax
mov eax,sm_mode
cmp eax,0100h
jae short smUseVESA
;--------------------------------------------------------------
; Prepare for BIOS call
;--------------------------------------------------------------
;ah=00 for mode set, al=mode
mov regs.realEAX,eax
jmp short smGo
smUseVESA:
;--------------------------------------------------------------
; Prepare for VESA call
;--------------------------------------------------------------
mov ax,04F02h ;ah=4F for VESA, al=02 for set mode
mov regs.realEAX,eax
mov eax,sm_mode ;bx = mode
mov regs.realEBX,eax
;--------------------------------------
; Simulate real interrupt through DPMI
;--------------------------------------
smGo:
mov bx,010h ;bh=0, bl=interrupt number
xor cx,cx ;copy zero words from stack
mov ax,ds ;es:edi points to regs
mov es,ax ;es:edi points to regs
mov edi,OFFSET regs
DPMI_SIMULATE_REAL_INT
;--------------------------------------------------------------
; Generate descriptor for video buffer at segment A000
;--------------------------------------------------------------
mov bx,VIDEO_SEGMENT ;segment to map
DPMI_MAP_SEG_TO_DESC
mov video_descriptor,ax
END_C_PROC
;-------------------------------------------------------------------------
; SVGAFunkyVideo()
; Deliberately create bad video sync
;-------------------------------------------------------------------------
; Enter:
; LWord mode = on/off (MUNGA "Logical")
;-------------------------------------------------------------------------
; Returns:
; (void)
;-------------------------------------------------------------------------
BEGIN_C_PROC SVGAFunkyVideo <eax,ebx,ecx,edi,es>
ARG_DWORD fv_mode
BUILD_STACK_FRAME
;--------------------------------------------------------------
; Enable writing to lowest seven CRTC registers
;--------------------------------------------------------------
mov dx,CRTC_INDEX ;point to vrend register
mov al,CRTC_INDEX_VREND
out dx,al
mov dx,CRTC_DATA ;get the current setting
in al,dx
mov cl,al ;save in cl
and al,07Fh ;turn off MSB (turns off write-protect)
out dx,al ;write it out
;--------------------------------------------------------------
; Point to CRTC htotal register
;--------------------------------------------------------------
mov dx,CRTC_INDEX ;point to htotal register
mov al,CRTC_INDEX_HTOTAL
out dx,al
mov dx,CRTC_DATA ;point dx at data port
;--------------------------------------------------------------
; Set or restore?
;--------------------------------------------------------------
mov eax,fv_mode
or eax,eax
je short bvOff
mov al,badVideoActive ;already in bad video?
or al,al
jnz bvExit ;yes, bail out
mov badVideoActive,1 ;flag as 'bad'
;--------------------------------------------------------------
; Read CRTC value, save it
;--------------------------------------------------------------
in al,dx ;get the current setting
mov crtc_htotal,al
;--------------------------------------------------------------
; Set screwed up CRTC value
;--------------------------------------------------------------
sub al,9 ;generate funky htotal
out dx,al ;write it out
jmp short bvExit
;--------------------------------------------------------------
; Restore proper CRTC value
;--------------------------------------------------------------
bvOff:
mov al,crtc_htotal
out dx,al
mov badVideoActive,0 ;flag as 'good'
bvExit:
;--------------------------------------------------------------
; Restore VREND register
;--------------------------------------------------------------
mov dx,CRTC_INDEX ;point to vrend register
mov al,CRTC_INDEX_VREND
out dx,al
mov dx,CRTC_DATA
mov al,cl ;get the old value
out dx,al ;write it out
END_C_PROC
;-------------------------------------------------------------------------
; SVGASetSplitterClock()
; Turn on/off special VWE splitter clock divider
;-------------------------------------------------------------------------
; Enter:
; LWord state = requested clock mode (True:on, False:off)
;-------------------------------------------------------------------------
; Returns:
; (void)
;-------------------------------------------------------------------------
BEGIN_C_PROC SVGASetSplitterClock <eax,edx>
ARG_DWORD state
BUILD_STACK_FRAME
mov eax,state
or eax,eax
jz short ssc_off
;--------------------------------------------------------------
; Turn on special splitter card clock divider
;--------------------------------------------------------------
mov dx,VWE_HC_ON
jmp short ssc_write
;--------------------------------------------------------------
; Turn off special splitter card clock divider
;--------------------------------------------------------------
ssc_off:
mov dx,VWE_HC_OFF
ssc_write:
out dx,al ;any value will do
END_C_PROC
;-------------------------------------------------------------------------
; SVGASetPage()
; Set SVGA display page
;-------------------------------------------------------------------------
; Enter:
; int page = requested SVGA page
;-------------------------------------------------------------------------
; Returns:
; (void)
;-------------------------------------------------------------------------
BEGIN_C_PROC SVGASetPage <eax,ebx,ecx,edx,esi,edi,es>
ARG_DWORD sp_page
BUILD_STACK_FRAME
mov edx,sp_page
and edx,00FFh ;remove upper bits
mov bx,0000h ;bh=set bank, bl=window #
mov ax,4F05h ;int 10h function 4F subfcn 05
;; cmp pageFunction,0 ;does the direct call exist?
;; je setBankIrq ;no, use interrupt
;; call cs:fword ptr [pageFunction] ;THIS DOES NOT WORK,
;; jmp setBankRest ;I suspect we must use a DPMI call.
;;setBankIrq:
mov ax,04F05h ;ah=4F for VESA, al=05 for set bank
mov regs.realEAX,eax
xor eax,eax ;bh = subfunction, bl=window
mov regs.realEBX,eax
mov regs.realEDX,edx ;dx = addr in granularity units
mov bx,010h ;bh=0, bl=interrupt number
xor cx,cx ;copy zero words from stack
mov ax,ds ;es:edi points to regs
mov es,ax
mov edi,OFFSET regs
DPMI_SIMULATE_REAL_INT
END_C_PROC
;-------------------------------------------------------------------------
; SVGATransfer32()
; Copy modified portions of buffer to SVGA display buffer
;-------------------------------------------------------------------------
; Enter:
; LWord offset = offset into display buffer
; Word *ptr = pointer to source pixels
; LWord bits = bits indicating which pixels to write
;-------------------------------------------------------------------------
; Returns:
; int number of bits transferred
;-------------------------------------------------------------------------
BEGIN_C_PROC SVGATransfer32 <ebx,ecx,edx,esi,edi,es>
ARG_DWORD t_dest_offset
ARG_DPTR t_source_ptr
ARG_DWORD t_bits
BUILD_STACK_FRAME
;-----------------------------
; Get source ptr in ds:si
;-----------------------------
mov esi,t_source_ptr
;-----------------------------
; Get dest ptr in es:di
;-----------------------------
mov ax,video_descriptor ;es:di points to destination
mov es,ax
mov edi,t_dest_offset
;-----------------------------
; Clear bit count
;-----------------------------
xor edx,edx
;-----------------------------
; Check 32 pixels
;-----------------------------
mov ebx,t_bits ;bx has bits
mov ecx,32
cld ;make sure esi, edi are INCREMENTED
tx_loop:
lodsw ;get source word
shl ebx,1 ;is bit set?
jnc tx_nope ;no, don't copy
;-----------------------------
; Bit set, copy the pixel
;-----------------------------
;; mov ax,testWord
;; inc ax
;; mov testWord,ax
stosw ;yes, copy
inc edx ;increment bit count
loop tx_loop
jmp short tx_done
;-----------------------------
; Bit clear, skip the pixel
;-----------------------------
tx_nope:
add edi,2
loop tx_loop
tx_done:
;-----------------------------
; All done, exit
;-----------------------------
mov eax,edx ;return count in eax
END_C_PROC
;-------------------------------------------------------------------------
; SVGATransfer32x()
; Copy LOWER BYTE of modified portions of buffer to SVGA display buffer
;-------------------------------------------------------------------------
; Enter:
; LWord offset = offset into display buffer
; Word *ptr = pointer to source pixels
; LWord bits = bits indicating which pixels to write
;-------------------------------------------------------------------------
; Returns:
; int number of bits transferred
;-------------------------------------------------------------------------
BEGIN_C_PROC SVGATransfer32x <ebx,ecx,edx,esi,edi,es>
ARG_DWORD t_dest_offsetx
ARG_DPTR t_source_ptrx
ARG_DWORD t_bitsx
BUILD_STACK_FRAME
;-----------------------------
; Get source ptr in ds:si
;-----------------------------
mov esi,t_source_ptrx
;-----------------------------
; Get dest ptr in es:di
;-----------------------------
mov ax,video_descriptor ;es:di points to destination
mov es,ax
mov edi,t_dest_offsetx
;-----------------------------
; Clear bit count
;-----------------------------
xor edx,edx
;-----------------------------
; Check 32 pixels
;-----------------------------
mov ebx,t_bitsx ;bx has bits
mov ecx,32
cld ;make sure esi, edi are INCREMENTED
tx_loopx:
lodsw ;get source word
shl ebx,1 ;is bit set?
jnc tx_nopex ;no, don't copy
;-----------------------------
; Bit set, copy the pixel
;-----------------------------
stosb ;yes, copy LOWER BYTE
inc edx ;increment bit count
loop tx_loopx
jmp short tx_donex
;-----------------------------
; Bit clear, skip the pixel
;-----------------------------
tx_nopex:
inc edi ;; LOWER BYTE ONLY
loop tx_loopx
tx_donex:
;-----------------------------
; All done, exit
;-----------------------------
mov eax,edx ;return count in eax
END_C_PROC
;-------------------------------------------------------------------------
; SVGAZeroPalette(port)
; Clear entire 256-color palette in hardware
; ASSUMES that the port is correct.
;-------------------------------------------------------------------------
; Enter:
; Word port = base port address
;-------------------------------------------------------------------------
; Returns:
; (void)
;-------------------------------------------------------------------------
BEGIN_C_PROC SVGAZeroPalette <eax,ebx,ecx,edx,esi,edi>
ARG_WORD zp_port
BUILD_STACK_FRAME
;--------------------------------------------------------------
; Signal CLUT that color data will be written
;--------------------------------------------------------------
mov dx,zp_port ;get port base address
xor al,al ;start with color zero
add dx,2 ;move to "write address" register
out dx,al ;set the address
;--------------------------------------------------------------
; Write the color data
;--------------------------------------------------------------
inc dx ;move to "data" register
mov ecx,256*3 ;clear entire palette
zpLoop:
out dx,al
loop zpLoop
END_C_PROC
;-------------------------------------------------------------------------
; SVGAWriteFullPalette(palette_ptr, port)
; Write entire 256-color palette to hardware
; ASSUMES that the palette pointer is correct.
; ASSUMES that the port is correct.
;-------------------------------------------------------------------------
; Enter:
; Palette8 *wp_source = pointer to FIRST COLOR TRIPLET
; Word port = base port address
;-------------------------------------------------------------------------
; Returns:
; (void)
;-------------------------------------------------------------------------
BEGIN_C_PROC SVGAWriteFullPalette <eax,ebx,ecx,edx,esi,edi>
ARG_DPTR wfp_source
ARG_WORD wfp_port
BUILD_STACK_FRAME
;--------------------------------------------------------------
; Convert color bytes to 6-bit VGA palette values
;--------------------------------------------------------------
mov esi,wfp_source ;get pointer to FIRST TRIPLET
mov edi,offset tempColor
mov ecx,256*3 ;transfer entire palette
cld ;make sure the pointers INCREMENT!
wfpLoop:
lodsb ;get the byte
shr al,2 ;change to six bits
stosb ;save the shifted data
loop wfpLoop ;do 'em all
;--------------------------------------------------------------
; Signal CLUT that color data will be written
;--------------------------------------------------------------
mov dx,wfp_port ;get port base address
xor al,al ;start with color zero
add dx,2 ;move to "write address" register
out dx,al ;set the address
;--------------------------------------------------------------
; Write the color data
;--------------------------------------------------------------
inc dx ;move to "data" register
mov esi,offset tempColor ;point to shifted data
mov ecx,256*3 ;transfer entire palette
rep outsb
END_C_PROC
;-------------------------------------------------------------------------
; SVGAReadFullPalette(palette_ptr, port)
; Read entire 256-color palette from hardware
; ASSUMES that the palette pointer is correct.
; ASSUMES that the port is correct.
;-------------------------------------------------------------------------
; Enter:
; Palette8 *rp_dest = pointer to FIRST COLOR TRIPLET
; Word port = base port address
;-------------------------------------------------------------------------
; Returns:
; (void)
;-------------------------------------------------------------------------
BEGIN_C_PROC SVGAReadFullPalette <eax,ebx,ecx,edx,esi,edi>
ARG_DPTR rfp_dest
ARG_WORD rfp_port
BUILD_STACK_FRAME
;--------------------------------------------------------------
; Signal CLUT that color data will be read
;--------------------------------------------------------------
mov dx,rfp_port ;get port base address
xor al,al ;start with color zero
add dx,1 ;move to "read address" register
out dx,al ;set the address
;--------------------------------------------------------------
; Read the color data
;--------------------------------------------------------------
add dx,2 ;move to "data" register
mov edi,rfp_dest ;point to destination
mov ecx,256*3 ;transfer entire palette
rfpLoop:
in al,dx ;get the color
shl al,2 ;convert to 8-bit data
stosb ;save it
loop rfpLoop
END_C_PROC
;-------------------------------------------------------------------------
; SVGAWritePaletteMask(port, mask)
; Set hardware palette mask
; ASSUMES that the port is correct.
;-------------------------------------------------------------------------
; Enter:
; Word port = base port address
; Byte mask = new mask value
;-------------------------------------------------------------------------
; Returns:
; (void)
;-------------------------------------------------------------------------
BEGIN_C_PROC SVGAWritePaletteMask <eax,ebx,ecx,edx,esi,edi>
ARG_WORD wpm_port
ARG_BYTE wpm_mask
BUILD_STACK_FRAME
;--------------------------------------------------------------
; Write the mask
;--------------------------------------------------------------
mov dx,wpm_port ;get port base address
mov al,wpm_mask
out dx,al
END_C_PROC
END_CODE
END