home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / dskutl / varvdisk.asm < prev    next >
Assembly Source File  |  1983-10-24  |  13KB  |  408 lines

  1. ;JS note, 8/1/83:  This version of the variable-size virtual disk
  2. ;   can handle up to 112 files.  There seems not to be any need 
  3. ;   to change to a "double-sided" drive, but one must take care
  4. ;   to zero out 7 sectors for the directory, rather than just the usual 4.
  5.  
  6.         PAGE    66,132
  7. ;
  8. ;       ******************************************************
  9. ;    *                 PROLOG                             *
  10. ;       *  THIS IS AN INSTALLABLE DEVICE DIVER FOR AN        *
  11. ;       *  IN STORAGE DISKETTE (VIRTUAL) WITH 180K CAPACITY. *
  12. ;       ******************************************************
  13. CSEG    SEGMENT    PARA PUBLIC 'CODE'
  14. ;
  15. ;    M A C R O ( S )
  16. ;
  17. STATUS    MACRO    STATE,ERR,RC
  18.     IFIDN    <STATE>,<DONE>
  19.      OR    ES:WORD PTR SRH_STA_FLD[BX],0100H
  20.        ENDIF
  21.     IFIDN    <STATE>,<BUSY>
  22.       OR      ES:WORD PTR SRH_STA_FLD[BX],0200H
  23.     ENDIF
  24.     IFIDN    <ERR>,<ERROR>
  25.      OR    ES:WORD PTR SRH_STA_FLD[BX],0100H
  26.     ENDIF
  27.     IFNB    <RC>
  28.      OR       ES:WORD PTR SRH_STA_FLD[BX],RC
  29.     ENDIF
  30.     ENDM
  31. ;
  32. ;    E Q U A T E S
  33. ;
  34. ;  READ/WRITE
  35. ;
  36. SRH         EQU    0        ;STATIC REQUEST HEADER START
  37. SRH_LEN         EQU   13        ;  "      "       "    LENGTH
  38. SRH_LEN_FLD  EQU   SRH        ;  "      "       "      "    FIELD
  39. SRH_UCD_FLD  EQU   SRH+1    ;  "      "       "    UNIT CODE FIELD
  40. SRH_CCD_FLD  EQU   SRH+2    ;  "      "       "    COMMAND CODE FIELD
  41. SRH_STA_FLD  EQU   SRH+3    ;  "      "       "    STATUS FIELD
  42. SRH_RES_FLD  EQU   SRH+5    ;  "      "       "    RESERVED AREA FIELD
  43. ;
  44. MD     EQU   SRH+SRH_LEN    ;MEDIA DESCRIPTOR BYTE
  45. MD_LEN     EQU   1        ;  "      "        "   LENGTH
  46. DTA     EQU   MD+MD_LEN    ;DISK TRANSFER ADDRESS
  47. DTA_LEN  EQU   4               ; DTA LENGTH
  48. COUNT     EQU   DTA+DTA_LEN    ;BYTE/SECTOR COUNT
  49. COUNT_LEN EQU  2         ; "     "      "    LENGTH
  50. SSN     EQU   COUNT+COUNT_LEN  ;STARTING SECTOR NUMBER
  51. SSN_LEN     EQU   2        ;   "       "      "     LENGTH
  52. ;
  53. ;  MEDIA CHECK
  54. ;
  55. RET_BYTE  EQU    MD+MD_LEN    ;BYTE RETURNED FROM DRIVER
  56. ;
  57. ; BUILD BPB
  58. ;
  59. BPBA_PTR     EQU  DTA+DTA_LEN    ;POINTER TO BPB
  60. BPBA_PTR_LEN EQU  4        ;   "     "  "  LENGTH
  61. ;
  62. ;  INIT
  63. ;
  64. UNITS       EQU   SRH+SRH_LEN
  65. UNITS_LEN   EQU   1
  66. BR_ADDR_0   EQU   UNITS+UNITS_LEN
  67. BR_ADDR_1   EQU   BR_ADDR_0+2
  68. BR_ADDR_LEN EQU   4
  69. BPB_PTR_OFF EQU   BR_ADDR_0+BR_ADDR_LEN
  70. BPB_PTR_SEG EQU   BPB_PTR_OFF+2
  71. ;
  72. ;
  73. VDSK     PROC    FAR
  74.          ASSUME    CS:CSEG,ES:CSEG,DS:CSEG
  75. BEGIN:
  76. START        EQU    $
  77. ;    S P E C I A L  D E V I C E  H E A D E R
  78. NEXT_DEV    DD    -1        ;POINTER TO NEXT DEVICE
  79. ATTRIBUTE    DW    2000H        ;BLOCK DEVICE (NON-IBM FORMAT)
  80. STRATEGY    DW    DEV_STRATEGY    ;POINTER TO DEVICE STRATEGY
  81. INTERRUPT    DW    DEV_INT        ;POINTER TO DEVICE INTERRUPT HANDLER
  82. DEV_NAME    DB    1        ;NUMBER OF BLOCK DEVICES
  83.         DB    7 DUP (?)    ;7 BYTES OF FILLER
  84. ;
  85. RH_OFF        DW    ?        ;REQUEST HEADER OFFSET
  86. RH_SEG        DW    ?        ;REQUEST HEADER SEGMENT
  87. ;  BIOS PARAMETER BLOCK
  88. BPB        EQU    $
  89.         DW    512        ;SECTOR SIZE
  90.         DB    2;(JS change)   ;SECTOR/ALLOCATION UNIT
  91.         DW    1        ;NUMBER OF RESERVED SECTORS
  92.         DB    2        ;NUMBER OF FATS
  93.         DW    112;(JS change)    ;NUMBER OF DIRECTORY ENTRIES
  94. SECTCT1        DW    ?        ;TOTAL NUMBER OF SECTORS
  95.         DB    0FCH;             ;MEDIA DESCRIPTOR
  96.         DW    2        ;NUMBER OF SECTORS OCCUPIED BY FAT
  97. ;
  98. BPB_PTR        DW    BPB        ;BIOS PARAMETER BLOCK POINTER ARRAY (1 ENTR)
  99. ;  CURRENT VIRTUAL DISK INFORMATION
  100. TOTAL        DW    ?        ;TOTAL SECTORS TO TRANSFER
  101. VERIFY        DB    0        ;VERIFY 1=YES, 0=NO
  102. START_SEC    DW    0        ;STARTING SECTOR NUMBER
  103. VDISK_PTR    DW    0        ;STARTING SEGMENT OF VIRTUAL DISK
  104. USER_DTA    DD    ?        ;POINTER TO CALLSER DISK TRANSFER ADDRESS
  105. BOOT_REC    EQU    $        ;DUMMY DOS BOOT RECORD
  106.         DB    3 DUP (0)    ;3 BYTE JUMP TO BOOT CODE (NOT BOOTABLE)
  107.         DB    'IBM  2.0'    ;VENDOR IDENTIFICATION
  108.         DW    512        ;NUMBER OF BYTES IN A SECTOR
  109.         DB    2;(JS change)      ;1 SECTOR PER ALLOCATION UNIT
  110.         DW    1        ;1 RESERVED SECTOR
  111.         DB    2        ;2 FATS
  112.         DW    112;(JS change)    ;NUMBER OF DIRECTORY ENTRIES
  113. SECTCT2        DW    ?        ;TOTAL SECTORS IN IMAGE
  114.         DB    0FCH;            ;TELLS DOS THIS IS A SINGLE SIDED 9 SECTOR
  115.         DW    2        ;NUMBER OF SECTORS IN FAT
  116. ;
  117. ;    FUNCTION TABLE
  118. ;
  119. FUNTAB        LABEL    BYTE
  120.         DW    INIT        ;INITIALIZATION
  121.         DW    MEDIA_CHECK    ;MEDIA CHECK (BLOCK ONLY)
  122.         DW    BUILD_BPB    ;BUILD BPB      "     "
  123.         DW    IOCTL_IN    ;IOCTL INPUT
  124.         DW    INPUT        ;INPUT (READ)
  125.         DW    ND_INPUT    ;NON_DESTRUCTIVE INPUT NO WAIT (CHAR ONLY)
  126.                 DW      IN_STAT        ;INPUT STATUS  (CHAR ONLY)
  127.         DW    IN_FLUSH        ;INPUT FLUSH      "   "
  128.         DW    OUTPUT        ;OUTPUT (WRITE)
  129.         DW    OUT_VERIFY    ;OUTPUT (WRITE) WITH VERIFY
  130.         DW    OUT_STAT    ;OUTPUT STATUS  (CHAR ONLY)
  131.         DW    OUT_FLUSH    ;OUTPUT FLUSH     "   "
  132.         DW    IOCTL_OUT    ;IOCTL OUTPUT
  133. ;
  134. ;  L O C A L  P R O C E D U R E S
  135. ;
  136. IN_SAVE        PROC    NEAR
  137.         MOV    AX,ES:WORD PTR DTA[BX]   ;SAVE CALLERS DTA
  138.         MOV    CS:USER_DTA,AX
  139.         MOV    AX,ES:WORD PTR DTA+2[BX]
  140.         MOV    CS:USER_DTA+2,AX
  141.         MOV    AX,ES:WORD PTR COUNT[BX]  ;GET NUMBER OF SECTOR TO TOTAL
  142.         XOR    AH,AH
  143.         MOV    CS:TOTAL,AX          ;MOVE NUMBER OF SECTORS TO TOTAL
  144.                 RET
  145. IN_SAVE        ENDP
  146. ;
  147. CALC_ADDR      PROC    NEAR
  148.         MOV    AX,CS:START_SEC    ;GET STARTING SECTOR NUMBER
  149.                 MOV     CX,20H        ;MOV 512 TO CX SEGMENT STYLE
  150.                 MUL    CX        ;MULTIPLY TO GET ACTUAL SECTOR
  151.         MOV    DX,CS:VDISK_PTR ;GET SEGMENT OF VIRTUAL DISK
  152.         ADD    DX,AX        ;ADD THAT SEGMENT TO INITIAL SEGMENT
  153.                 MOV    DS,DX        ;SAVE THAT AS THE ACTUAL SEGMENT
  154.                 XOR    SI,SI        ;IT'S ON A PARAGRAPH BOUNDRY
  155.         MOV    AX,CS:TOTAL    ;TOTAL NUMBER OF SECTOR TO READ
  156.         MOV    CX,512        ;BYTES PER SECTOR
  157.         MUL    CX        ;MULTIPLY TO GET COPY LENGTH
  158.         OR    AX,AX        ;CHECK FOR GREATER THAN 64K
  159.         JNZ    MOVE_IT
  160.         MOV    AX,0FFFFH       ;MOVE IN FOR 64K
  161. MOVE_IT:
  162.         XCHG    CX,AX        ;MOVE LENGTH TO CX
  163.         RET
  164. CALC_ADDR       ENDP
  165. ;
  166. SECTOR_READ    PROC    NEAR
  167.         CALL    CALC_ADDR       ;CALCULATE THE STARTING 'SECTOR'
  168.                 MOV    ES,CS:USER_DTA+2 ;SET DESTINATION (ES:DI) TO POINT
  169.                 MOV    DI,CS:USER_DTA     ;TO CALLERS DTA
  170. ;
  171. ;  CHECK FOR DTA WRAP IN CASE WE CAME THROUGH VIA VERIFY
  172. ;
  173.         MOV    AX,DI        ;GET OFFSET OF DTA
  174.         ADD    AX,CX        ;ADD COPY LENGTH TO IT
  175.         JNC    READ_COPY       ;CARRY FLAG = 0, NO WRAP
  176.         MOV    AX,0FFFFH    ;MAX LENGTH
  177.         SUB    AX,DI        ;SUBTRACT DTA OFFSET FROM MAX
  178.         MOV    CX,AX        ;USE THAT AS COPY LENGTH TO AVOID WRAP
  179. READ_COPY:
  180. REP        MOVSB            ;DO THE 'READ'
  181.         RET
  182. SECTOR_READ     ENDP
  183. ;
  184. SECTOR_WRITE PROC    NEAR
  185.         CALL    CALC_ADDR       ;CALCULATE STARTING 'SECTOR'
  186.         PUSH    DS
  187.         POP    ES        ;ESTABLISH ADDRESSABILITY
  188.         MOV    DI,SI        ; ES:DI POINT TO 'DISK`
  189.         MOV    DS,CS:USER_DTA+2 ; DS:SI POINT TO CALLERS DTA
  190.         MOV    SI,CS:USER_DTA
  191. ;
  192. ; CHECK FOR DTA WRAP
  193. ;
  194.         MOV    AX,SI        ;MOVE DTA OFFSET TO AX
  195.         ADD    AX,CX        ;ADD COPY LENGTH TO OFFSET
  196.         JNC    WRITE_COPY    ;CARRY FLAG = 0, NO SEGMENT WRAP
  197.                 MOV    AX,0FFFFH    ;MOVE IN MAX COPY LENGTH
  198.         SUB    AX,SI        ;SUTRACT DTA OFFSET FROM MAX
  199.         MOV    CX,AX        ;USE AS NEW COPY LENGTH TO AVOID WRAP
  200. WRITE_COPY:
  201. REP        MOVSB            ;DO THE 'WRITE'
  202.         RET
  203. SECTOR_WRITE    ENDP
  204. ;
  205. ;  D E V I C E  S T R A T E G Y
  206. ;
  207. DEV_STRATEGY:
  208.         MOV    CS:RH_SEG,ES    ;SAVE SEGMENT OF REQUEST HEADER POINTER
  209.                 MOV    CS:RH_OFF,BX    ;SAVE OFFSET OF   "       "...
  210.         RET
  211. ;
  212. ;  D E V I C E  I N T E R R U P T  H A N D L E R
  213. ;
  214. DEV_INT:
  215. ;  PRESERVE MACHINE STATE ON ENTRY
  216.         CLD
  217.         PUSH    DS
  218.         PUSH    ES
  219.         PUSH    AX
  220.         PUSH    BX
  221.         PUSH    CX
  222.         PUSH    DX
  223.         PUSH    DI
  224.         PUSH    SI
  225. ;
  226. ;  DO THE BRANCH ACCORDING TO THE FUNCTION PASSED
  227. ;
  228.         MOV    AL,ES:[BX]+2    ;GET FUNCTION BYTE
  229.         ROL    AL,1        ;GET OFFSET INTO TABLE
  230.         LEA    DI,FUNTAB    ;GET ADDRESS OF FUNCTION TABLE
  231.         XOR    AH,AH
  232.         ADD    DI,AX
  233.                 MOV     BX,CS:RH_OFF    ;See PC Age 2.6,
  234.                 MOV     ES,CS:RH_SEG    ;  p. 65.  (JS)
  235.         JMP    WORD PTR[DI]
  236. ;
  237. ;   INIT
  238. ;
  239. INIT:
  240.         PUSH    CS
  241.         POP    DX        ;CURRENT CS TO DX
  242. ;
  243.                 PUSH    ES              ;JS modification:
  244.                 MOV     AX,0            ;  Load number of kilobytes
  245.                 MOV     ES,AX           ;   from last half of last
  246.                 MOV     AX,ES:3FEH      ;   "interrupt" slot, convert
  247.                 SAL     AX,1            ;   to number of sectors,
  248.                 MOV     CS:SECTCT1,AX   ;   and store result.
  249.                 MOV     CS:SECTCT2,AX
  250.                 POP     ES
  251. ;
  252.         LEA    AX,CS:VDISK    ;GET ADDRESS OF VIRTUAL DISK
  253.         MOV    CL,4
  254.             ROR    AX,CL        ;DIVIDE BY 16 (PARAGRAPH FORM)
  255.         ADD    DX,AX        ;ADD TO CURRENT CS VALUE
  256.         MOV    CS:VDISK_PTR,DX ;SAVE AS STARTING SEGMENT OF VIRTUAL DISK
  257.                 MOV    AX,SECTCT1    ; ADD ENOUGH PARAGRAPHS TO STARTING
  258.                 MOV     CL,5            ;    SEGMENT OF VIRTUAL DISK
  259.                 SAL     AX,CL
  260.                 ADD    DX,AX        
  261.         MOV    ES:WORD PTR BR_ADDR_0[BX],0
  262.         MOV    ES:BR_ADDR_1[BX],DX      ;MAKE THAT THE BREAK ADDRESS
  263.                 MOV    ES:BYTE PTR UNITS[BX],1  ;NUMBER OF DISKETTE UNITS
  264.                 LEA    DX,BPB_PTR           ;GET ADDRESS OF BPB POINTER ARRAY
  265.                 MOV    ES:BPB_PTR_OFF[BX],DX  ;SAVE OFFSET IN DATA PACKET
  266.                 MOV    ES:BPB_PTR_SEG[BX],CS  ;SAVE SEGMENT IN DATA PACKET
  267.                 MOV    ES,CS:VDISK_PTR        ;GET STARTING SECTOR OF VIRTUAL DISK
  268.                 XOR    DI,DI               ;ZERO OUT DI (BOOT RECORD)
  269.                 LEA    SI,BOOT_REC           ;ADDRESS OF BOOT RECORD
  270.                 MOV    CX,24
  271. REP        MOVSB                   ;COPY 24 BYTES OF BOOT RECORD
  272.         MOV    CS:WORD PTR START_SEC,1
  273.         MOV    CS:WORD PTR TOTAL,2
  274.          CALL    CALC_ADDR    ;CALCULATE ADDRESS OF LOGICAL SECTOR 1
  275.                 PUSH    DS
  276.         POP    ES
  277.         MOV    DI,SI        ;MOVE THAT ADDRES TO ES:DI
  278.         XOR     AL,AL
  279. REP        STOSB                           ;ZERO OUT FAT AREA
  280.         MOV    DS:BYTE PTR [SI],0FCH    ;SET THE FIRST FAT ENTRY
  281.                 MOV    DS:BYTE PTR 1[SI],0FFH
  282.         MOV    DS:BYTE PTR 2[SI],0FFH
  283.         PUSH    DS            ;SAVE POINTER TO FAT
  284.         PUSH    SI            ;          ON THE STACK
  285.         MOV    CS:WORD PTR START_SEC,3
  286.         MOV    CS:WORD PTR TOTAL,2
  287.         CALL    CALC_ADDR        ;CALCULATE ADDRESS OF LOGICAL SECTOR 3
  288.                 PUSH    DS
  289.         POP    ES
  290.         MOV    DI,SI            ;MOVE THAT ADDRESS TO ES:DI
  291.                 POP    SI
  292.         POP    DS            ;RESTORE ADDRESS TO FIRST FAT
  293. REP        MOVSB             ;COPY FIRST FAT TO SECOND FAT
  294.                 MOV    CS:WORD PTR START_SEC,5
  295.         MOV    CS:WORD PTR TOTAL,7;(JS change)
  296.         CALL    CALC_ADDR        ;CALCULATE ADDR OF L.S. 5 (START OF DIR)
  297.                 XOR    AL,AL
  298.         PUSH    DS
  299.         POP    ES            ;SET UP ES:DI TO POINT T
  300.             XOR    DI,DI
  301. REP        STOSB                ;ZERO OUT DIRECTORY
  302.         MOV    ES,CS:RH_SEG        ;RESTORE ES:BX TO REQUEST HEADER
  303.                 MOV    BX,CS:RH_OFF
  304.         STATUS  DONE,NOERROR,0        ;SET STATUS WORD (DONE, NOERROR)
  305.         JMP    EXIT
  306. ;
  307. ;  MEDIA CHECK
  308. ;
  309. MEDIA_CHECK:                    ;MEDIA CHECK (BLOCK ONLY)
  310. ;
  311. ;  SET MEDIA NOT CHANGED
  312. ;
  313.         MOV    ES:BYTE PTR RET_BYTE[BX],1  ;STORE IN RETURN BYTE
  314.                 STATUS  DONE,NOERROR,0
  315.         JMP    EXIT
  316. ;
  317. ;  BUILD BIOS PARAMETER BLOCK
  318. ;
  319. BUILD_BPB:
  320.         PUSH    ES        ;SAVE SRH SEGMENT
  321.         PUSH    BX        ;SAVE SRH OFFSET
  322.         MOV    CS:WORD PTR START_SEC,0
  323.         MOV    CS:WORD PTR TOTAL,1
  324.         CALL    CALC_ADDR
  325.         PUSH    CS
  326.         POP    ES
  327.         LEA    DI,BPB        ;ADDRESS OF BIOS PARAMETER BLOCK
  328.                 ADD    SI,11        ;ADD 11 TO SI
  329.           MOV    CX,13        ;LENGTH OF BPB
  330. REP        MOVSB
  331.         POP    BX        ;RESTORE OFFSET OF SRH
  332.         POP    ES        ;RESTORE SEGMENT OF SRH
  333.         LEA    DX,BPB        ;GET BPB ARRAY POINTER
  334.         MOV    ES:BPBA_PTR[BX],DX  ;SAVE PTR TO BPB TABLE
  335.         MOV    ES:BPBA_PTR+2[BX],CS
  336.         MOV    ES:DTA[BX],DX ;OFFSET OF SECTOR BUFFER
  337.         MOV    ES:DTA+2[BX],CS
  338.         STATUS    DONE,NOERROR,0
  339.         JMP    EXIT
  340. ;
  341. ;  THE FOLLOWING ENTRIES ARE FOR NOT SUPPORTED BY THIS DEVICE
  342. ;
  343. IOCTL_IN:
  344. IOCTL_OUT:
  345. ND_INPUT:            ;NON_DESTRUCTIVE INPUT NO WAIT (CHAR ONLY)
  346. IN_STAT:            ;INPUT STATUS "    "....
  347. IN_FLUSH:            ;INPUT FLUSH  "    "....
  348. OUT_STAT:             ;OUTPUT STATUS"    "....
  349. OUT_FLUSH:            ;OUTPUT FLUSH "    "....
  350. ;
  351. ;  DISK READ
  352. ;
  353. INPUT:
  354.         CALL    IN_SAVE        ;CALL THE INITIAL SAVE ROUTINE
  355.         MOV    AX,ES:WORD PTR SSN[BX]  ;SET STARTING SECTOR NUMBER
  356.                 MOV    CS:START_SEC,AX        ;SAVE STARTING SECTOR NUMBER
  357.                 MOV    AX,ES:WORD PTR COUNT[BX]
  358.         MOV    CS:TOTAL,AX        ;SAVE TOTAL SECTORS TO TRANSFER
  359.                 CALL    SECTOR_READ        ;READ IN THAT MANY SECTORS
  360.                 MOV    BX,CS:RH_OFF        ;RESTORE ES:BX AS REQUEST HEADER POINTER
  361.                 MOV    ES,CS:RH_SEG
  362.         STATUS    DONE,NOERROR,0
  363.         JMP    EXIT
  364. ;
  365. ;  DISK WRITE
  366. ;
  367. OUTPUT:                        ;OUTPUT (WRITE)
  368.         CALL    IN_SAVE
  369.         MOV    AX,ES:WORD PTR SSN[BX]  ;GET STARTING SECTOR NUMBER
  370.                 MOV    CS:START_SEC,AX        ;SET "        "......
  371.         MOV    AX,ES:WORD PTR COUNT[BX]
  372.         MOV    CS:TOTAL,AX        ;SAVE TOTAL SECTORS TO WRITE
  373.                 CALL    SECTOR_WRITE        ;WRITE OUT THOSE SECTORS
  374.         MOV    BX,CS:RH_OFF        ;RESTORE ES:BX AS REQUEST HEADER POINTER
  375.                 MOV    ES,CS:RH_SEG
  376.         CMP    CS:BYTE PTR VERIFY,0    ;WRITE VERIFY SET
  377.         JZ NO_VERIFY        ;NO, NO WRITE VERIFY
  378.         MOV    CS:BYTE PTR VERIFY,0    ;RESET VERIFY INDICATOR
  379.         JMP    INPUT            ;READ THOSE SECTORS BACK IN
  380. NO_VERIFY:
  381.         STATUS    DONE,NOERROR,0        ;SET DONE, NO EROR IN STATUS WORD
  382.               JMP    EXIT
  383. OUT_VERIFY:                    ;OUTPUT (WRITE) WITH VERIFY
  384.                   MOV    CS:BYTE PTR VERIFY,1    ;SET THE VERIFY FLAG
  385.         JMP    OUTPUT            ;BRANCH TO OUTPUT ROUTINE
  386. ;
  387. ;  COMMON EXIT
  388. ;
  389. EXIT:
  390.         POP    SI        ;RESTORE ALL OF THE REGISTERS
  391.         POP    DI
  392.         POP    DX
  393.         POP    CX
  394.         POP    BX
  395.         POP    AX
  396.         POP    ES
  397.         POP    DS
  398.         RET
  399. E_O_P:
  400. ; MACRO TO ALIGN THE VIRTUAL DISK ON A PARAGRAPH BOUNDARY
  401. IF ($-START) MOD 16
  402. ORG     ($-START)+16-(($-START) MOD 16)
  403. ENDIF
  404. VDISK        EQU    $
  405. VDSK        ENDP
  406. CSEG        ENDS
  407.         END    BEGIN
  408.