wolf3d

The original open source release of Wolfenstein 3D
Log | Files | Refs

ID_VL_A.ASM (13243B)


      1 ; ID_VL.ASM
      2 
      3 	IDEAL
      4 	MODEL	MEDIUM,C
      5 
      6 	INCLUDE	'ID_VL.EQU'
      7 
      8 SCREENSEG	=	0a000h
      9 
     10 	DATASEG
     11 
     12 	EXTRN	TimeCount:WORD		; incremented every 70th of a second
     13 	EXTRN	linewidth:WORD
     14 
     15 starttime	dw	?
     16 
     17 	CODESEG
     18 
     19 ;===========================================================================
     20 
     21 
     22 ;==============
     23 ;
     24 ; VL_WaitVBL			******** NEW *********
     25 ;
     26 ; Wait for the vertical retrace (returns before the actual vertical sync)
     27 ;
     28 ;==============
     29 
     30 PROC	VL_WaitVBL  num:WORD
     31 PUBLIC	VL_WaitVBL
     32 @@wait:
     33 
     34 	mov	dx,STATUS_REGISTER_1
     35 
     36 	mov	cx,[num]
     37 ;
     38 ; wait for a display signal to make sure the raster isn't in the middle
     39 ; of a sync
     40 ;
     41 @@waitnosync:
     42 	in	al,dx
     43 	test	al,8
     44 	jnz	@@waitnosync
     45 
     46 
     47 @@waitsync:
     48 	in	al,dx
     49 	test	al,8
     50 	jz	@@waitsync
     51 
     52 	loop	@@waitnosync
     53 
     54 	ret
     55 
     56 ENDP
     57 
     58 
     59 ;===========================================================================
     60 
     61 ;==============
     62 ;
     63 ; VL_SetCRTC
     64 ;
     65 ;==============
     66 
     67 PROC	VL_SetCRTC  crtc:WORD
     68 PUBLIC	VL_SetCRTC
     69 
     70 ;
     71 ; wait for a display signal to make sure the raster isn't in the middle
     72 ; of a sync
     73 ;
     74 	cli
     75 
     76 	mov	dx,STATUS_REGISTER_1
     77 
     78 @@waitdisplay:
     79 	in	al,dx
     80 	test	al,1	;1 = display is disabled (HBL / VBL)
     81 	jnz	@@waitdisplay
     82 
     83 
     84 ;
     85 ; set CRTC start
     86 ;
     87 ; for some reason, my XT's EGA card doesn't like word outs to the CRTC
     88 ; index...
     89 ;
     90 	mov	cx,[crtc]
     91 	mov	dx,CRTC_INDEX
     92 	mov	al,0ch		;start address high register
     93 	out	dx,al
     94 	inc	dx
     95 	mov	al,ch
     96 	out	dx,al
     97 	dec	dx
     98 	mov	al,0dh		;start address low register
     99 	out	dx,al
    100 	mov	al,cl
    101 	inc	dx
    102 	out	dx,al
    103 
    104 
    105 	sti
    106 
    107 	ret
    108 
    109 ENDP
    110 
    111 
    112 
    113 ;===========================================================================
    114 
    115 ;==============
    116 ;
    117 ; VL_SetScreen
    118 ;
    119 ;==============
    120 
    121 PROC	VL_SetScreen  crtc:WORD, pel:WORD
    122 PUBLIC	VL_SetScreen
    123 
    124 
    125 	mov	cx,[timecount]		; if timecount goes up by two, the retrace
    126 	add	cx,2				; period was missed (an interrupt covered it)
    127 
    128 	mov	dx,STATUS_REGISTER_1
    129 
    130 ;
    131 ; wait for a display signal to make sure the raster isn't in the middle
    132 ; of a sync
    133 ;
    134 @@waitdisplay:
    135 	in	al,dx
    136 	test	al,1	;1 = display is disabled (HBL / VBL)
    137 	jnz	@@waitdisplay
    138 
    139 
    140 @@loop:
    141 	sti
    142 	jmp	$+2
    143 	cli
    144 
    145 	cmp	[timecount],cx		; will only happen if an interrupt is
    146 	jae	@@setcrtc			; straddling the entire retrace period
    147 
    148 ;
    149 ; when several succesive display not enableds occur,
    150 ; the bottom of the screen has been hit
    151 ;
    152 
    153 	in	al,dx
    154 	test	al,8
    155 	jnz	@@waitdisplay
    156 	test	al,1
    157 	jz	@@loop
    158 
    159 	in	al,dx
    160 	test	al,8
    161 	jnz	@@waitdisplay
    162 	test	al,1
    163 	jz	@@loop
    164 
    165 	in	al,dx
    166 	test	al,8
    167 	jnz	@@waitdisplay
    168 	test	al,1
    169 	jz	@@loop
    170 
    171 	in	al,dx
    172 	test	al,8
    173 	jnz	@@waitdisplay
    174 	test	al,1
    175 	jz	@@loop
    176 
    177 	in	al,dx
    178 	test	al,8
    179 	jnz	@@waitdisplay
    180 	test	al,1
    181 	jz	@@loop
    182 
    183 
    184 @@setcrtc:
    185 
    186 
    187 ;
    188 ; set CRTC start
    189 ;
    190 ; for some reason, my XT's EGA card doesn't like word outs to the CRTC
    191 ; index...
    192 ;
    193 	mov	cx,[crtc]
    194 	mov	dx,CRTC_INDEX
    195 	mov	al,0ch		;start address high register
    196 	out	dx,al
    197 	inc	dx
    198 	mov	al,ch
    199 	out	dx,al
    200 	dec	dx
    201 	mov	al,0dh		;start address low register
    202 	out	dx,al
    203 	mov	al,cl
    204 	inc	dx
    205 	out	dx,al
    206 
    207 ;
    208 ; set horizontal panning
    209 ;
    210 	mov	dx,ATR_INDEX
    211 	mov	al,ATR_PELPAN or 20h
    212 	out	dx,al
    213 	jmp	$+2
    214 	mov	al,[BYTE pel]		;pel pan value
    215 	out	dx,al
    216 
    217 	sti
    218 
    219 	ret
    220 
    221 ENDP
    222 
    223 
    224 ;===========================================================================
    225 
    226 
    227 ;============================================================================
    228 ;
    229 ; VL_ScreenToScreen
    230 ;
    231 ; Basic block copy routine.  Copies one block of screen memory to another,
    232 ; using write mode 1 (sets it and returns with write mode 0).  bufferofs is
    233 ; NOT accounted for.
    234 ;
    235 ;============================================================================
    236 
    237 PROC	VL_ScreenToScreen	source:WORD, dest:WORD, wide:WORD, height:WORD
    238 PUBLIC	VL_ScreenToScreen
    239 USES	SI,DI
    240 
    241 	pushf
    242 	cli
    243 
    244 	mov	dx,SC_INDEX
    245 	mov	ax,SC_MAPMASK+15*256
    246 	out	dx,ax
    247 	mov	dx,GC_INDEX
    248 	mov	al,GC_MODE
    249 	out	dx,al
    250 	inc	dx
    251 	in	al,dx
    252 	and	al,NOT 3
    253 	or	al,1
    254 	out	dx,al
    255 
    256 	popf
    257 
    258 	mov	bx,[linewidth]
    259 	sub	bx,[wide]
    260 
    261 	mov	ax,SCREENSEG
    262 	mov	es,ax
    263 	mov	ds,ax
    264 
    265 	mov	si,[source]
    266 	mov	di,[dest]				;start at same place in all planes
    267 	mov	dx,[height]				;scan lines to draw
    268 	mov	ax,[wide]
    269 
    270 @@lineloop:
    271 	mov	cx,ax
    272 	rep	movsb
    273 	add	si,bx
    274 	add	di,bx
    275 
    276 	dec	dx
    277 	jnz	@@lineloop
    278 
    279 	mov	dx,GC_INDEX+1
    280 	in	al,dx
    281 	and	al,NOT 3
    282 	out	dx,al
    283 
    284 	mov	ax,ss
    285 	mov	ds,ax					;restore turbo's data segment
    286 
    287 	ret
    288 
    289 ENDP
    290 
    291 
    292 ;===========================================================================
    293 
    294 
    295 	MASM
    296 ;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
    297 ;
    298 ; Name:	VL_VideoID
    299 ;
    300 ; Function:	Detects the presence of various video subsystems
    301 ;
    302 ; int VideoID;
    303 ;
    304 ; Subsystem ID values:
    305 ; 	 0  = (none)
    306 ; 	 1  = MDA
    307 ; 	 2  = CGA
    308 ; 	 3  = EGA
    309 ; 	 4  = MCGA
    310 ; 	 5  = VGA
    311 ; 	80h = HGC
    312 ; 	81h = HGC+
    313 ; 	82h = Hercules InColor
    314 ;
    315 ;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
    316 
    317 ;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
    318 ;
    319 ; Equates
    320 ;
    321 ;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
    322 VIDstruct	STRUC		; corresponds to C data structure
    323 
    324 Video0Type	DB	?	; first subsystem type
    325 Display0Type	DB	? 	; display attached to first subsystem
    326 
    327 Video1Type	DB	?	; second subsystem type
    328 Display1Type	DB	?	; display attached to second subsystem
    329 
    330 VIDstruct	ENDS
    331 
    332 
    333 Device0	EQU	word ptr Video0Type[di]
    334 Device1	EQU	word ptr Video1Type[di]
    335 
    336 
    337 MDA	EQU	1	; subsystem types
    338 CGA	EQU	2
    339 EGA	EQU	3
    340 MCGA	EQU	4
    341 VGA	EQU	5
    342 HGC	EQU	80h
    343 HGCPlus	EQU	81h
    344 InColor	EQU	82h
    345 
    346 MDADisplay	EQU	1	; display types
    347 CGADisplay	EQU	2
    348 EGAColorDisplay	EQU	3
    349 PS2MonoDisplay	EQU	4
    350 PS2ColorDisplay	EQU	5
    351 
    352 TRUE	EQU	1
    353 FALSE	EQU	0
    354 
    355 ;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
    356 ;
    357 ; Program
    358 ;
    359 ;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
    360 
    361 Results	VIDstruct <>	;results go here!
    362 
    363 EGADisplays	DB	CGADisplay	; 0000b, 0001b	(EGA switch values)
    364 	DB	EGAColorDisplay	; 0010b, 0011b
    365 	DB	MDADisplay	; 0100b, 0101b
    366 	DB	CGADisplay	; 0110b, 0111b
    367 	DB	EGAColorDisplay	; 1000b, 1001b
    368 	DB	MDADisplay	; 1010b, 1011b
    369 
    370 DCCtable	DB	0,0	; translate table for INT 10h func 1Ah
    371 	DB	MDA,MDADisplay
    372 	DB	CGA,CGADisplay
    373 	DB	0,0
    374 	DB	EGA,EGAColorDisplay
    375 	DB	EGA,MDADisplay
    376 	DB	0,0
    377 	DB	VGA,PS2MonoDisplay
    378 	DB	VGA,PS2ColorDisplay
    379 	DB	0,0
    380 	DB	MCGA,EGAColorDisplay
    381 	DB	MCGA,PS2MonoDisplay
    382 	DB	MCGA,PS2ColorDisplay
    383 
    384 TestSequence	DB	TRUE	; this list of flags and addresses
    385 	DW	FindPS2	;  determines the order in which this
    386 			;  program looks for the various
    387 EGAflag	DB	?	;  subsystems
    388 	DW	FindEGA
    389 
    390 CGAflag	DB	?
    391 	DW	FindCGA
    392 
    393 Monoflag	DB	?
    394 	DW	FindMono
    395 
    396 NumberOfTests	EQU	($-TestSequence)/3
    397 
    398 
    399 PUBLIC	VL_VideoID
    400 VL_VideoID	PROC
    401 
    402 	push	bp	; preserve caller registers
    403 	mov	bp,sp
    404 	push	ds
    405 	push	si
    406 	push	di
    407 
    408 	push	cs
    409 	pop	ds
    410 	ASSUME	DS:@Code
    411 
    412 ; initialize the data structure that will contain the results
    413 
    414 	lea	di,Results	; DS:DI -> start of data structure
    415 
    416 	mov	Device0,0	; zero these variables
    417 	mov	Device1,0
    418 
    419 ; look for the various subsystems using the subroutines whose addresses are
    420 ; tabulated in TestSequence; each subroutine sets flags in TestSequence
    421 ; to indicate whether subsequent subroutines need to be called
    422 
    423 	mov	byte ptr CGAflag,TRUE
    424 	mov	byte ptr EGAflag,TRUE
    425 	mov	byte ptr Monoflag,TRUE
    426 
    427 	mov	cx,NumberOfTests
    428 	mov	si,offset TestSequence
    429 
    430 @@L01:	lodsb		; AL := flag
    431 	test	al,al
    432 	lodsw		; AX := subroutine address
    433 	jz	@@L02	; skip subroutine if flag is false
    434 
    435 	push	si
    436 	push	cx
    437 	call	ax	; call subroutine to detect subsystem
    438 	pop	cx
    439 	pop	si
    440 
    441 @@L02:	loop	@@L01
    442 
    443 ; determine which subsystem is active
    444 
    445 	call	FindActive
    446 
    447 	mov	al,Results.Video0Type
    448 	mov	ah,0	; was:  Results.Display0Type
    449 
    450 	pop	di	; restore caller registers and return
    451 	pop	si
    452 	pop	ds
    453 	mov	sp,bp
    454 	pop	bp
    455 	ret
    456 
    457 VL_VideoID	ENDP
    458 
    459 
    460 ;
    461 ; FindPS2
    462 ;
    463 ; This subroutine uses INT 10H function 1Ah to determine the video BIOS
    464 ; Display Combination Code (DCC) for each video subsystem present.
    465 ;
    466 
    467 FindPS2	PROC	near
    468 
    469 	mov	ax,1A00h
    470 	int	10h	; call video BIOS for info
    471 
    472 	cmp	al,1Ah
    473 	jne	@@L13	; exit if function not supported (i.e.,
    474 			;  no MCGA or VGA in system)
    475 
    476 ; convert BIOS DCCs into specific subsystems & displays
    477 
    478 	mov	cx,bx
    479 	xor	bh,bh	; BX := DCC for active subsystem
    480 
    481 	or	ch,ch
    482 	jz	@@L11	; jump if only one subsystem present
    483 
    484 	mov	bl,ch	; BX := inactive DCC
    485 	add	bx,bx
    486 	mov	ax,[bx+offset DCCtable]
    487 
    488 	mov	Device1,ax
    489 
    490 	mov	bl,cl
    491 	xor	bh,bh	; BX := active DCC
    492 
    493 @@L11:	add	bx,bx
    494 	mov	ax,[bx+offset DCCtable]
    495 
    496 	mov	Device0,ax
    497 
    498 ; reset flags for subsystems that have been ruled out
    499 
    500 	mov	byte ptr CGAflag,FALSE
    501 	mov	byte ptr EGAflag,FALSE
    502 	mov	byte ptr Monoflag,FALSE
    503 
    504 	lea	bx,Video0Type[di]  ; if the BIOS reported an MDA ...
    505 	cmp	byte ptr [bx],MDA
    506 	je	@@L12
    507 
    508 	lea	bx,Video1Type[di]
    509 	cmp	byte ptr [bx],MDA
    510 	jne	@@L13
    511 
    512 @@L12:	mov	word ptr [bx],0    ; ... Hercules can't be ruled out
    513 	mov	byte ptr Monoflag,TRUE
    514 
    515 @@L13:	ret
    516 
    517 FindPS2	ENDP
    518 
    519 
    520 ;
    521 ; FindEGA
    522 ;
    523 ; Look for an EGA.  This is done by making a call to an EGA BIOS function
    524 ;  which doesn't exist in the default (MDA, CGA) BIOS.
    525 
    526 FindEGA	PROC	near	; Caller:	AH = flags
    527 			; Returns:	AH = flags
    528 			;		Video0Type and
    529 			;		 Display0Type updated
    530 
    531 	mov	bl,10h	; BL := 10h (return EGA info)
    532 	mov	ah,12h	; AH := INT 10H function number
    533 	int	10h	; call EGA BIOS for info
    534 			; if EGA BIOS is present,
    535 			;  BL <> 10H
    536 			;  CL = switch setting
    537 	cmp	bl,10h
    538 	je	@@L22	; jump if EGA BIOS not present
    539 
    540 	mov	al,cl
    541 	shr	al,1	; AL := switches/2
    542 	mov	bx,offset EGADisplays
    543 	xlat		; determine display type from switches
    544 	mov	ah,al	; AH := display type
    545 	mov	al,EGA	; AL := subystem type
    546 	call	FoundDevice
    547 
    548 	cmp	ah,MDADisplay
    549 	je	@@L21	; jump if EGA has a monochrome display
    550 
    551 	mov	CGAflag,FALSE	; no CGA if EGA has color display
    552 	jmp	short @@L22
    553 
    554 @@L21:	mov	Monoflag,FALSE	; EGA has a mono display, so MDA and
    555 			;  Hercules are ruled out
    556 @@L22:	ret
    557 
    558 FindEGA	ENDP
    559 
    560 ;
    561 ; FindCGA
    562 ;
    563 ; This is done by looking for the CGA's 6845 CRTC at I/O port 3D4H.
    564 ;
    565 FindCGA	PROC	near	; Returns:	VIDstruct updated
    566 
    567 	mov	dx,3D4h	; DX := CRTC address port
    568 	call	Find6845
    569 	jc	@@L31	; jump if not present
    570 
    571 	mov	al,CGA
    572 	mov	ah,CGADisplay
    573 	call	FoundDevice
    574 
    575 @@L31:	ret
    576 
    577 FindCGA	ENDP
    578 
    579 ;
    580 ; FindMono
    581 ;
    582 ; This is done by looking for the MDA's 6845 CRTC at I/O port 3B4H.  If
    583 ; a 6845 is found, the subroutine distinguishes between an MDA
    584 ; and a Hercules adapter by monitoring bit 7 of the CRT Status byte.
    585 ; This bit changes on Hercules adapters but does not change on an MDA.
    586 ;
    587 ; The various Hercules adapters are identified by bits 4 through 6 of
    588 ; the CRT Status value:
    589 ;
    590 ; 000b = HGC
    591 ; 001b = HGC+
    592 ; 101b = InColor card
    593 ;
    594 
    595 FindMono	PROC	near	; Returns:	VIDstruct updated
    596 
    597 	mov	dx,3B4h	; DX := CRTC address port
    598 	call	Find6845
    599 	jc	@@L44	; jump if not present
    600 
    601 	mov	dl,0BAh	; DX := 3BAh (status port)
    602 	in	al,dx
    603 	and	al,80h
    604 	mov	ah,al	; AH := bit 7 (vertical sync on HGC)
    605 
    606 	mov	cx,8000h	; do this 32768 times
    607 @@L41:	in	al,dx
    608 	and	al,80h	; isolate bit 7
    609 	cmp	ah,al
    610 	loope	@@L41	; wait for bit 7 to change
    611 	jne	@@L42	; if bit 7 changed, it's a Hercules
    612 
    613 	mov	al,MDA	; if bit 7 didn't change, it's an MDA
    614 	mov	ah,MDADisplay
    615 	call	FoundDevice
    616 	jmp	short @@L44
    617 
    618 @@L42:	in	al,dx
    619 	mov	dl,al	; DL := value from status port
    620 	and	dl,01110000b	; mask bits 4 thru 6
    621 
    622 	mov	ah,MDADisplay	; assume it's a monochrome display
    623 
    624 	mov	al,HGCPlus	; look for an HGC+
    625 	cmp	dl,00010000b
    626 	je	@@L43	; jump if it's an HGC+
    627 
    628 	mov	al,HGC	; look for an InColor card or HGC
    629 	cmp	dl,01010000b
    630 	jne	@@L43	; jump if it's not an InColor card
    631 
    632 	mov	al,InColor	; it's an InColor card
    633 	mov	ah,EGAColorDisplay
    634 
    635 @@L43:	call	FoundDevice
    636 
    637 @@L44:	ret
    638 
    639 FindMono	ENDP
    640 
    641 ;
    642 ; Find6845
    643 ;
    644 ; This routine detects the presence of the CRTC on a MDA, CGA or HGC.
    645 ; The technique is to write and read register 0Fh of the chip (cursor
    646 ; low).  If the same value is read as written, assume the chip is
    647 ; present at the specified port addr.
    648 ;
    649 
    650 Find6845	PROC	near	; Caller:  DX = port addr
    651 			; Returns: cf set if not present
    652 	mov	al,0Fh
    653 	out	dx,al	; select 6845 reg 0Fh (Cursor Low)
    654 	inc	dx
    655 	in	al,dx	; AL := current Cursor Low value
    656 	mov	ah,al	; preserve in AH
    657 	mov	al,66h	; AL := arbitrary value
    658 	out	dx,al	; try to write to 6845
    659 
    660 	mov	cx,100h
    661 @@L51:	loop	@@L51	; wait for 6845 to respond
    662 
    663 	in	al,dx
    664 	xchg	ah,al	; AH := returned value
    665 			; AL := original value
    666 	out	dx,al	; restore original value
    667 
    668 	cmp	ah,66h	; test whether 6845 responded
    669 	je	@@L52	; jump if it did (cf is reset)
    670 
    671 	stc		; set carry flag if no 6845 present
    672 
    673 @@L52:	ret
    674 
    675 Find6845	ENDP
    676 
    677 
    678 ;
    679 ; FindActive
    680 ;
    681 ; This subroutine stores the currently active device as Device0.  The
    682 ; current video mode determines which subsystem is active.
    683 ;
    684 
    685 FindActive	PROC	near
    686 
    687 	cmp	word ptr Device1,0
    688 	je	@@L63	; exit if only one subsystem
    689 
    690 	cmp	Video0Type[di],4	; exit if MCGA or VGA present
    691 	jge	@@L63	;  (INT 10H function 1AH
    692 	cmp	Video1Type[di],4	;  already did the work)
    693 	jge	@@L63
    694 
    695 	mov	ah,0Fh
    696 	int	10h	; AL := current BIOS video mode
    697 
    698 	and	al,7
    699 	cmp	al,7	; jump if monochrome
    700 	je	@@L61	;  (mode 7 or 0Fh)
    701 
    702 	cmp	Display0Type[di],MDADisplay
    703 	jne	@@L63	; exit if Display0 is color
    704 	jmp	short @@L62
    705 
    706 @@L61:	cmp	Display0Type[di],MDADisplay
    707 	je	@@L63	; exit if Display0 is monochrome
    708 
    709 @@L62:	mov	ax,Device0	; make Device0 currently active
    710 	xchg	ax,Device1
    711 	mov	Device0,ax
    712 
    713 @@L63:	ret
    714 
    715 FindActive	ENDP
    716 
    717 
    718 ;
    719 ; FoundDevice
    720 ;
    721 ; This routine updates the list of subsystems.
    722 ;
    723 
    724 FoundDevice	PROC	near	; Caller:    AH = display #
    725 			;	     AL = subsystem #
    726 			; Destroys:  BX
    727 	lea	bx,Video0Type[di]
    728 	cmp	byte ptr [bx],0
    729 	je	@@L71	; jump if 1st subsystem
    730 
    731 	lea	bx,Video1Type[di]	; must be 2nd subsystem
    732 
    733 @@L71:	mov	[bx],ax	; update list entry
    734 	ret
    735 
    736 FoundDevice	ENDP
    737 
    738 IDEAL
    739 
    740 
    741 
    742 END