home *** CD-ROM | disk | FTP | other *** search
/ The Unsorted BBS Collection / thegreatunsorted.tar / thegreatunsorted / misc / disk.asm < prev    next >
Assembly Source File  |  1990-04-17  |  71KB  |  1,849 lines

  1.     Page    58,132
  2.     Title    DISK.ASM    Disk Controller
  3. ;******************************************************************************
  4. ;
  5. ;   Name:    DISK.ASM    Disk Controller
  6. ;
  7. ;   Group:    Emulator
  8. ;
  9. ;   Revision:    1.00
  10. ;
  11. ;   Date:    January 30, 1988
  12. ;
  13. ;   Author:    Randy W. Spurlock
  14. ;
  15. ;******************************************************************************
  16. ;
  17. ;  Module Functional Description:
  18. ;
  19. ;        This module contains all the code for the Apple
  20. ;    disk drive controller.
  21. ;
  22. ;******************************************************************************
  23. ;
  24. ;  Changes:
  25. ;
  26. ;    DATE     REVISION                DESCRIPTION
  27. ;  --------   --------    -------------------------------------------------------
  28. ;   1/30/88    1.00    Original
  29. ;
  30. ;******************************************************************************
  31.     Page
  32. ;
  33. ;  Public Declarations
  34. ;
  35.     Public    Disk_ID         ; Disk controller ID string
  36.     Public    Disk_Init        ; Disk controller initialize routine
  37.     Public    Disk_Ctrl        ; Disk controller control routine
  38.     Public    Disk_Rd         ; Disk controller read routine
  39.     Public    Disk_Wrt        ; Disk controller write routine
  40.     Public    Disk_Mem_Rd        ; Disk controller memory read routine
  41.     Public    Disk_Mem_Wrt        ; Disk controller memory write routine
  42.     Public    Disk_Exp_Rd        ; Disk ctrl. expansion read routine
  43.     Public    Disk_Exp_Wrt        ; Disk ctrl. expansion write routine
  44.     Public    Disk_Data        ; Disk controller data segment pointers
  45. ;
  46. ;  External Declarations
  47. ;
  48.     Extrn    Slot_Address:Near    ; Get expansion slot address   (DEVICE)
  49.     Extrn    Error:Near        ; Apple emulator error routine    (APPLE)
  50.     Extrn    Exit:Near        ; Apple emulator exit routine    (APPLE)
  51.     Extrn    Disk_ROM:Word        ; Apple disk ctrl. ROM file name (DATA)
  52.     Extrn    Current_Slot:Byte    ; Current active slot number     (DATA)
  53.     Extrn    ERR_NO_DISK_FILE:Abs    ; No disk ROM file error code     (DATA)
  54.     Extrn    ERR_BAD_DISK_FILE:Abs    ; Bad disk ROM file error code     (DATA)
  55.     Extrn    ERR_BAD_DISK_IMAGE:abs    ; Bad disk ROM image error code  (DATA)
  56.     Extrn    ERR_NO_MEMORY:Abs    ; Not enough memory error code     (DATA)
  57. ;
  58. ;  LOCAL Equates
  59. ;
  60. DISK_SIZE    Equ    0100h        ; Apple disk controller ROM size (Bytes)
  61. CTRL_SIZE    Equ    030Ah        ; Disk controller memory size (12K)
  62. BUFFER_SIZE    Equ    0020h        ; Pre-nibblization buffer size (.5K)
  63. TRACK_SIZE    Equ    0100h        ; Track buffer size (4K)
  64. ASCII_CONVERT    Equ    4130h        ; ASCII conversion value (Drive/Slot)
  65. FLAG_INIT    Equ    04        ; Disk flag init. value (Disk present)
  66. PHASE_INIT    Equ    00h        ; Disk phase initialization value
  67. CONTROL_MASK    Equ    0Fh        ; Disk controller control bits mask
  68. READ        Equ    01h        ; Read only file attribute bit
  69. DRIVE_A     Equ    00h        ; Drive A selected value
  70. DRIVE_B     Equ    01h        ; Drive B selected value
  71. DISK_PROTECT    Equ    80h        ; Apple disk drive protect bit
  72. HIDDEN        Equ    02h        ; Hidden file attribute bit
  73. SYSTEM        Equ    04h        ; System file attribute bit
  74. SEARCH_ATTR    Equ    HIDDEN+SYSTEM    ; File search attribute (Hidden/System)
  75. PHASE_INCREMENT Equ    001h        ; Phase increment value (+1)
  76. PHASE_DECREMENT Equ    0FFh        ; Phase decrement value (-1)
  77. PHASE_WRAP    Equ    03h        ; Phase wrap check value (3)
  78. PHASE_MAX    Equ    50h        ; Maximum phase value + 1 (80)
  79. GAP_1        Equ    40h        ; Gap 1 size (64 Bytes)
  80. GAP_2        Equ    08h        ; Gap 2 size (8 Bytes)
  81. GAP_3        Equ    08h        ; Gap 3 size (8 Bytes)
  82. COUNT_13    Equ    0Dh        ; 13 Sector disk sector limit value
  83. COUNT_16    Equ    10h        ; 16 Sector disk sector limit value
  84. SELF_SYNC    Equ    0FFh        ; Self sync byte value (Gap filler byte)
  85. TRACK_MASK    Equ    0FEh        ; Track phase mask value
  86. SECTOR_MASK    Equ    0FF00h        ; Sector pointer mask value
  87. DISK_VOLUME    Equ    0FEh        ; Dummy disk volume number
  88. PRO_ADDR_1    Equ    0D5h        ; Address
  89. PRO_ADDR_2    Equ    0AAh        ;      mark prologue
  90. PRO_ADDR_3    Equ    096h        ;            string value
  91. EPI_ADDR_1    Equ    0DEh        ; Address
  92. EPI_ADDR_2    Equ    0AAh        ;      mark epilogue
  93. EPI_ADDR_3    Equ    0EBh        ;            string value
  94. PRO_DATA_1    Equ    0D5h        ; Data
  95. PRO_DATA_2    Equ    0AAh        ;      mark prologue
  96. PRO_DATA_3    Equ    0ADh        ;             string value
  97. EPI_DATA_1    Equ    0DEh        ; Data
  98. EPI_DATA_2    Equ    0AAh        ;      mark epilogue
  99. EPI_DATA_3    Equ    0EBh        ;             string value
  100. NIBBLE_BREAK    Equ    0100h        ; Nibble buffer sector break point
  101. START_5_3    Equ    0033h        ; Starting byte for 5 to 3 nibblization
  102. BREAK_5_3    Equ    009Ah        ; Break point for 5 to 3 nibblization
  103. START_6_2    Equ    0001h        ; Starting byte for 6 to 2 nibblization
  104. BREAK_6_2    Equ    0056h        ; Break point for 6 to 2 nibblization
  105. DECODE_MASK    Equ    7Fh        ; Decode bits mask value
  106. ;
  107. ;  Define any include files needed
  108. ;
  109.     Include     Macros.inc    ; Include the macro definitions
  110.     Include     Equates.inc    ; Include the equate definitions
  111.     Include     Strucs.inc    ; Include the structure definitions
  112.     .286c                ; Include 80286 instructions
  113.     Page
  114. ;
  115. ;  Define the emulator code segment
  116. ;
  117. Emulate Segment Word Public 'EMULATE'   ; Emulator code segment
  118.     Assume    cs:Emulate, ds:Nothing, es:Nothing
  119.     Subttl    Disk_Init    Disk Controller Initialization
  120.     Page    +
  121. ;******************************************************************************
  122. ;
  123. ;    Disk_Init(RAM_Space, Slot_Number)
  124. ;
  125. ;        Call routine to get expansion slot address
  126. ;        Try to open the Disk Controller ROM data file
  127. ;        If no errors opening the Disk Controller ROM file
  128. ;            Try to read in the Disk Controller ROM image
  129. ;            If errors reading the Disk Controller ROM
  130. ;                Set error code to bad Disk Controller ROM file
  131. ;                Call the error routine
  132. ;                Call routine to exit the emulator
  133. ;            Endif
  134. ;            Close the Disk Controller ROM file
  135. ;            If nibblization buffer has not been allocated
  136. ;                Try to allocate memory for nibblization
  137. ;                If errors allocating memory
  138. ;                    Set error code to not enough memory
  139. ;                    Call the error routine
  140. ;                    Call routine to exit the emulator
  141. ;                Endif
  142. ;                Save nibblization buffer segment
  143. ;                Try to allocate memory for track buffer
  144. ;                If errors allocating memory
  145. ;                    Set error code to not enough memory
  146. ;                    Call the error routine
  147. ;                    Call routine to exit the emulator
  148. ;                Endif
  149. ;                Save track buffer segment
  150. ;            Endif for nibblization buffer
  151. ;            Try to allocate memory for the disk controller
  152. ;            If no errors allocating memory
  153. ;                Save address of disk controller data area
  154. ;            Else not enough memory available
  155. ;                Set error code to not enough memory
  156. ;                Call the error routine
  157. ;                Call routine to exit the emulator
  158. ;            Endif
  159. ;            Initialize the disk controller current drive (Drive A)
  160. ;            Initialize drive file names
  161. ;            Initialize disk flag value
  162. ;            Initialize drive phase values
  163. ;            Initialize drive track buffer pointer
  164. ;            Initialize track limit value (16 Sector)
  165. ;            Initialize track buffer size (16 Sector)
  166. ;            Initialize sector limit value (16)
  167. ;            Try to get information on the disk file
  168. ;            If no errors getting information
  169. ;                Try to open the disk file
  170. ;                If no errors opening the disk file
  171. ;                    If a system type file (13 Sector)
  172. ;                        Set the old style flag bit
  173. ;                        Update track limit (13 Sector)
  174. ;                        Update track size (13 Sector)
  175. ;                        Update sector limit (13)
  176. ;                    Endif for system type file
  177. ;                Else error opening the disk file
  178. ;                    Zero the file handle (No disk file)
  179. ;                    Clear disk present flag bit
  180. ;                Endif for opening disk file
  181. ;            Else error getting information
  182. ;                Zero the disk file handle
  183. ;                Clear disk present flag bit
  184. ;            Endif for getting information
  185. ;            Save the disk file handle
  186. ;        Else errors opening the Disk Controller ROM file
  187. ;            Set error code to no Disk Controller ROM file
  188. ;            Call the error routine
  189. ;            Call routine to exit the emulator
  190. ;        Endif
  191. ;        Return to the caller
  192. ;
  193. ;    Registers on Entry:
  194. ;
  195. ;        AX    - Slot number (0 - 7)
  196. ;        DS    - 65C02 RAM space
  197. ;
  198. ;    Registers on Exit:
  199. ;
  200. ;        AX-DX - Destroyed
  201. ;        SI-DI - Destroyed
  202. ;
  203. ;******************************************************************************
  204.         Even            ; Force procedure to even address
  205. Disk_Init    Proc    Near        ; Disk controller init. procedure
  206.     mov    di,ax            ; Get the disk controller slot number
  207.     shl    di,1            ; Convert slot number to table index
  208.     call    Slot_Address        ; Call routine to get slot address
  209.     mov    ax,cs            ; Get the current code segment value
  210.     mov    bx,ds            ; Save 65C02 RAM space segment value
  211.     mov    ds,ax            ; Setup to open the disk ROM file
  212.     mov    ah,OPEN_FILE        ; Get the open file function code
  213.     mov    al,READ_ONLY        ; Get the read file access code
  214.     lea    dx,cs:[Disk_ROM]    ; Get pointer to disk ROM file name
  215.     int    DOS            ; Try to open the disk ROM file
  216.     jnc    Read_Disk_ROM        ; Jump if no errors opening file
  217.     mov    al,ERR_NO_DISK_FILE    ; Get no disk ROM file error code
  218. Disk_ROM_Error:
  219.     call    Error            ; Call routine to print the error
  220.     call    Exit            ; Call routine to exit emulator
  221. Read_Disk_ROM:
  222.     mov    ds,bx            ; Restore 65C02 RAM space segment value
  223.     mov    bx,ax            ; Move file handle to BX register
  224.     mov    ah,READ_FILE        ; Get read file function code
  225.     mov    dx,si            ; Setup the data buffer address
  226.     mov    cx,DISK_SIZE        ; Get the disk ROM image size (.25k)
  227.     int    DOS            ; Try to read the disk ROM image
  228.     mov    cx,ax            ; Save ROM image size in CX register
  229.     mov    al,ERR_BAD_DISK_FILE    ; Get bad disk ROM file error code
  230.     jc    Disk_ROM_Error        ; Jump if error trying to read the file
  231.     cmp    cx,DISK_SIZE        ; Check for all of image read in
  232.     mov    al,ERR_BAD_DISK_IMAGE    ; Get bad disk ROM image error code
  233.     jne    Disk_ROM_Error        ; Jump if part of image missing
  234.     mov    ah,CLOSE_FILE        ; Get close file function code
  235.     int    DOS            ; Close the disk ROM file
  236.     mov    ax,cs:[Nibble_Save]    ; Get nibblization buffer segment
  237.     or    ax,ax            ; Check for buffer area allocated
  238.     jnz    Disk_Allocate        ; Jump if area already allocated
  239.     mov    ah,ALLOCATE_MEMORY    ; Get the allocate memory function code
  240.     mov    bx,BUFFER_SIZE        ; Get number of paragraphs to allocate
  241.     int    DOS            ; Try to allocate the ROM save area
  242.     jnc    Track_Allocate        ; Jump if no errors allocating space
  243. Memory_Error:
  244.     mov    al,ERR_NO_MEMORY    ; Get not enough memory error code
  245.     call    Error            ; Call routine to print the error
  246.     call    Exit            ; Call routine to exit the emulator
  247. Track_Allocate:
  248.     mov    cs:[Nibble_Save],ax    ; Save nibblization segment value
  249.     mov    ah,ALLOCATE_MEMORY    ; Get the allocate memory function code
  250.     mov    bx,TRACK_SIZE        ; Get number of paragraphs to allocate
  251.     int    DOS            ; Try to allocate the ROM save area
  252.     jc    Memory_Error        ; Jump if errors allocating space
  253.     mov    cs:[Track_Save],ax    ; Save track buffer segment value
  254. Disk_Allocate:
  255.     mov    ah,ALLOCATE_MEMORY    ; Get the allocate memory function code
  256.     mov    bx,CTRL_SIZE        ; Get number of paragraphs to allocate
  257.     int    DOS            ; Try to allocate disk controller space
  258.     jc    Memory_Error        ; Jump if errors allocating space
  259.     Save    ds,es            ; Save the DS and ES register values
  260.     mov    ds,ax            ; Setup disk controller segment address
  261.     mov    cs:[di + Disk_Data],ax    ; Save disk controller segment address
  262.     mov    ds:[Disk_Current],Disk_Drive_A
  263.     mov    ax,ds            ; Get the disk controller segment
  264.     mov    es,ax            ; Set ES to disk controller segment
  265.     mov    ax,cs            ; Get current CS register value
  266.     mov    ds,ax            ; Set DS to current CS register value
  267.     mov    dx,di            ; Get the disk controller slot index
  268.     shr    dx,1            ; Convert slot index to slot number
  269.     add    dx,ASCII_CONVERT    ; Convert drive/slot to ASCII
  270.     lea    si,cs:[Base_File]    ; Get pointer to base file name
  271.     mov    di,Disk_Drive_A.Disk_File
  272.     mov    cx,Size Disk_Name    ; Get length of the base file name
  273.     rep    movsb            ; Setup base file name for drive A
  274.     lea    si,cs:[Base_File]    ; Get pointer to base file name
  275.     mov    di,Disk_Drive_B.Disk_File
  276.     mov    cx,Size Disk_Name    ; Get length of the base file name
  277.     rep    movsb            ; Setup base file name for drive B
  278.     mov    es:[Disk_Drive_A.Disk_File.Disk_Slot],dl
  279.     mov    es:[Disk_Drive_A.Disk_File.Disk_Letter],dh
  280.     inc    dh            ; Increment the drive letter
  281.     mov    es:[Disk_Drive_B.Disk_File.Disk_Slot],dl
  282.     mov    es:[Disk_Drive_B.Disk_File.Disk_Letter],dh
  283.     mov    ah,SET_DTA        ; Get set DTA function code
  284.     lea    dx,cs:[Find_Data]    ; Get pointer to find match data area
  285.     int    DOS            ; Set DTA to the find match data area
  286.     mov    ax,es            ; Get disk controller card segment
  287.     mov    ds,ax            ; Set DS to disk controller segment
  288. Initialize_Values:
  289.     xor    ax,ax            ; Setup AX as a zero value
  290.     mov    ds:[Disk_Drive_A.Disk_Flag],FLAG_INIT
  291.     mov    ds:[Disk_Drive_B.Disk_Flag],FLAG_INIT
  292.     mov    ds:[Disk_Drive_A.Disk_Last],PHASE_INIT
  293.     mov    ds:[Disk_Drive_B.Disk_Last],PHASE_INIT
  294.     mov    ds:[Disk_Drive_A.Disk_Curr],PHASE_INIT
  295.     mov    ds:[Disk_Drive_B.Disk_Curr],PHASE_INIT
  296.     mov    ds:[Disk_Drive_A.Disk_Pointer],ax
  297.     mov    ds:[Disk_Drive_B.Disk_Pointer],ax
  298.     mov    ds:[Disk_Drive_A.Disk_Limit],Size Track_16
  299.     mov    ds:[Disk_Drive_B.Disk_Limit],Size Track_16
  300.     mov    ds:[Disk_Drive_A.Disk_Track],Size Buffer_16
  301.     mov    ds:[Disk_Drive_B.Disk_Track],Size Buffer_16
  302.     mov    ds:[Disk_Drive_A.Disk_Sector],COUNT_16
  303.     mov    ds:[Disk_Drive_B.Disk_Sector],COUNT_16
  304.     mov    ds:[Disk_Current],Disk_Drive_A
  305. Check_File_A:
  306.     mov    ah,FIND_FIRST        ; Get find first function code
  307.     mov    cx,SEARCH_ATTR        ; Get the search attribute byte
  308.     mov    dx,Disk_Drive_A.Disk_File
  309.     int    DOS            ; Get information on drive A file
  310.     jc    Error_File_A        ; Jump if error on information call
  311. Open_Drive_A:
  312.     mov    ah,OPEN_FILE        ; Get the open file function code
  313.     mov    al,READ_WRITE        ; Get read/write file access code
  314.     mov    dx,Disk_Drive_A.Disk_File
  315.     test    Byte Ptr cs:[Find_Data.File_Attr],READ
  316.     jz    Open_File_A        ; Jump if file is not write only
  317.     mov    al,READ_ONLY        ; Get read only file access code
  318. Open_File_A:
  319.     int    DOS            ; Try to open disk drive A file
  320.     jnc    Set_A_Handle        ; Jump if no errors opening the file
  321. Error_File_A:
  322.     xor    ax,ax            ; Zero the handle number (No disk)
  323.     and    ds:[Disk_Drive_A.Disk_Flag],Not DISK_PRESENT
  324. Set_A_Handle:
  325.     mov    ds:[Disk_Drive_A.Disk_Handle],ax
  326.     or    ax,ax            ; Check for error opening the file
  327.     jz    Check_File_B        ; Jump if error opening the file
  328. Check_Type_A:
  329.     test    Byte Ptr cs:[Find_Data.File_Attr],SYSTEM
  330.     jz    Check_Protect_A     ; Jump if NOT an old style disk file
  331.     or    ds:[Disk_Drive_A.Disk_Flag],OLD_STYLE
  332.     mov    ds:[Disk_Drive_A.Disk_Limit],Size Track_13
  333.     mov    ds:[Disk_Drive_A.Disk_Track],Size Buffer_13
  334.     mov    ds:[Disk_Drive_A.Disk_Sector],COUNT_13
  335. Check_Protect_A:
  336.     test    Byte Ptr cs:[Find_Data.File_Attr],READ
  337.     jz    Check_File_B        ; Jump if NOT a read only disk file
  338.     or    ds:[Disk_Drive_A.Disk_Flag],WRITE_PROTECT
  339. Check_File_B:
  340.     mov    ah,FIND_FIRST        ; Get find first function code
  341.     mov    cx,SEARCH_ATTR        ; Get the search attribute byte
  342.     mov    dx,Disk_Drive_B.Disk_File
  343.     int    DOS            ; Get information on drive B file
  344.     jc    Error_File_B        ; Jump if error on information call
  345. Open_Drive_B:
  346.     mov    ah,OPEN_FILE        ; Get the open file function code
  347.     mov    al,READ_WRITE        ; Get read/write file access code
  348.     mov    dx,Disk_Drive_B.Disk_File
  349.     test    Byte Ptr cs:[Find_Data.File_Attr],READ
  350.     jz    Open_File_B        ; Jump if file is not write only
  351.     mov    al,READ_ONLY        ; Get read only file access code
  352. Open_File_B:
  353.     int    DOS            ; Try to open disk drive B file
  354.     jnc    Set_B_Handle        ; Jump if no errors opening the file
  355. Error_File_B:
  356.     xor    ax,ax            ; Zero the handle number (No disk)
  357.     and    ds:[Disk_Drive_B.Disk_Flag],Not DISK_PRESENT
  358. Set_B_Handle:
  359.     mov    ds:[Disk_Drive_B.Disk_Handle],ax
  360.     or    ax,ax            ; Check for error opening the file
  361.     jz    Disk_Exit        ; Jump if error opening the file
  362. Check_Type_B:
  363.     test    Byte Ptr cs:[Find_Data.File_Attr],SYSTEM
  364.     jz    Check_Protect_B     ; Jump if NOT an old style disk file
  365.     or    ds:[Disk_Drive_B.Disk_Flag],OLD_STYLE
  366.     mov    ds:[Disk_Drive_B.Disk_Limit],Size Track_13
  367.     mov    ds:[Disk_Drive_B.Disk_Track],Size Buffer_13
  368.     mov    ds:[Disk_Drive_B.Disk_Sector],COUNT_13
  369. Check_Protect_B:
  370.     test    Byte Ptr cs:[Find_Data.File_Attr],READ
  371.     jz    Disk_Exit        ; Jump if NOT a read only disk file
  372.     or    ds:[Disk_Drive_B.Disk_Flag],WRITE_PROTECT
  373. Disk_Exit:
  374.     Restore ds,es            ; Restore the DS and ES register values
  375.     ret                ; Return to the caller
  376. Disk_Init    Endp            ; End of the Disk_Init procedure
  377.     Subttl    Disk_Ctrl    Disk Controller Control
  378.     Page    +
  379. ;******************************************************************************
  380. ;
  381. ;    Disk_Ctrl(RAM_Space, Slot_Number)
  382. ;
  383. ;
  384. ;        Return to the caller
  385. ;
  386. ;    Registers on Entry:
  387. ;
  388. ;        AX    - Slot number (0 - 7)
  389. ;        DS    - 65C02 RAM space
  390. ;
  391. ;    Registers on Exit:
  392. ;
  393. ;        AX-DX - Destroyed
  394. ;        SI-DI - Destroyed
  395. ;
  396. ;******************************************************************************
  397.         Even            ; Force procedure to even address
  398. Disk_Ctrl    Proc    Near        ; Disk controller control procedure
  399.  
  400.     ret                ; Return to the caller
  401. Disk_Ctrl    Endp            ; End of the Disk_Ctrl procedure
  402.     Subttl    Disk_Rd     Disk Controller Read
  403.     Page    +
  404. ;******************************************************************************
  405. ;
  406. ;    Disk_Rd(Effective_Address, Slot_Index)
  407. ;
  408. ;        Save the required registers
  409. ;        Setup the disk controller data segment
  410. ;        Get the disk controller control bits (From effective address)
  411. ;        Call the correct routine to handle the update
  412. ;        Restore the required registers
  413. ;        Return to the caller
  414. ;
  415. ;    Registers on Entry:
  416. ;
  417. ;        BP    - Slot index (Slot number * 2)
  418. ;        DS:DI - 65C02 Effective address
  419. ;
  420. ;    Registers on Exit:
  421. ;
  422. ;        AL    - Disk value
  423. ;        BP    - Destroyed
  424. ;
  425. ;******************************************************************************
  426.         Even            ; Force procedure to even address
  427. Disk_Rd     Proc    Near        ; Disk controller read procedure
  428.     Save    bx,es            ; Save the required registers
  429.     mov    es,cs:[bp + Disk_Data]    ; Setup disk controller data segment
  430.     mov    bx,di            ; Get the effective address
  431.     and    bx,CONTROL_MASK     ; Mask off all but the control bits
  432.     shl    bx,1            ; Convert control bits to table index
  433.     call    cs:[bx + Disk_Table]    ; Call correct routine to handle update
  434. Disk_Rd_Exit:
  435.     Restore bx,es            ; Restore the required registers
  436.     ret                ; Return to the caller
  437. Disk_Rd     Endp            ; End of the Disk_Rd procedure
  438.     Subttl    Disk_Wrt    Disk Controller Write
  439.     Page    +
  440. ;******************************************************************************
  441. ;
  442. ;    Disk_Wrt(Effective_Address, Slot_Index, Memory_Value)
  443. ;
  444. ;        Save the required registers
  445. ;        Setup the disk controller data segment
  446. ;        Get the disk controller control bits (From effective address)
  447. ;        Call the correct routine to handle the update
  448. ;        Restore the required registers
  449. ;        Return to the caller
  450. ;
  451. ;    Registers on Entry:
  452. ;
  453. ;        AL    - Memory value
  454. ;        BP    - Slot index (Slot number * 2)
  455. ;        DS:DI - 65C02 Effective address
  456. ;
  457. ;    Registers on Exit:
  458. ;
  459. ;        BP    - Destroyed
  460. ;
  461. ;******************************************************************************
  462.         Even            ; Force procedure to even address
  463. Disk_Wrt    Proc    Near        ; Disk controller write procedure
  464.     Save    ax,bx,es        ; Save the required registers
  465.     mov    es,cs:[bp + Disk_Data]    ; Setup disk controller data segment
  466.     mov    bx,di            ; Get the effective address
  467.     and    bx,CONTROL_MASK     ; Mask off all but the control bits
  468.     shl    bx,1            ; Convert control bits to table index
  469.     call    cs:[bx + Disk_Table]    ; Call correct routine to handle update
  470. Disk_Wrt_Exit:
  471.     Restore ax,bx,es        ; Restore the required registers
  472.     ret                ; Return to the caller
  473. Disk_Wrt    Endp            ; End of the Disk_Wrt procedure
  474.     Subttl    Disk_Mem_Rd    Disk Controller Memory Read
  475.     Page    +
  476. ;******************************************************************************
  477. ;
  478. ;    Disk_Mem_Rd(Effective_Address)
  479. ;
  480. ;        Read the memory location value (Byte)
  481. ;        Return to the caller
  482. ;
  483. ;    Registers on Entry:
  484. ;
  485. ;        DS:DI - 65C02 Effective address
  486. ;
  487. ;    Registers on Exit:
  488. ;
  489. ;        AL    - Memory value
  490. ;
  491. ;******************************************************************************
  492.         Even            ; Force procedure to even address
  493. Disk_Mem_Rd    Proc    Near        ; Disk controller memory read procedure
  494.     mov    al,ds:[di]        ; Read the memory location
  495.     ret                ; Return to the caller
  496. Disk_Mem_Rd    Endp            ; End of the Disk_Mem_Rd procedure
  497.     Subttl    Disk_Mem_Wrt    Disk Controller Memory Write
  498.     Page    +
  499. ;******************************************************************************
  500. ;
  501. ;    Disk_Mem_Wrt(Effective_Address)
  502. ;
  503. ;        Return to the caller (ROM is NOT writable)
  504. ;
  505. ;    Registers on Entry:
  506. ;
  507. ;        AL    - Memory value
  508. ;        DS:DI - 65C02 Effective address
  509. ;
  510. ;    Registers on Exit:
  511. ;
  512. ;        None
  513. ;
  514. ;******************************************************************************
  515.         Even            ; Force procedure to even address
  516. Disk_Mem_Wrt    Proc    Near        ; Disk controller memory write procedure
  517.     ret                ; Return to the caller
  518. Disk_Mem_Wrt    Endp            ; End of the Disk_Mem_Wrt procedure
  519.     Subttl    Disk_Exp_Rd    Disk Controller Expansion Read
  520.     Page    +
  521. ;******************************************************************************
  522. ;
  523. ;    Disk_Exp_Rd(Effective_Address)
  524. ;
  525. ;        Read the memory location value (Byte)
  526. ;        Return to the caller
  527. ;
  528. ;    Registers on Entry:
  529. ;
  530. ;        DS:DI - 65C02 Effective address
  531. ;
  532. ;    Registers on Exit:
  533. ;
  534. ;        AL    - Memory value
  535. ;
  536. ;******************************************************************************
  537.         Even            ; Force procedure to even address
  538. Disk_Exp_Rd    Proc    Near        ; Disk ctrl. expansion read procedure
  539.     mov    al,ds:[di]        ; Read the memory location
  540.     ret                ; Return to the caller
  541. Disk_Exp_Rd    Endp            ; End of the Disk_Exp_Rd procedure
  542.     Subttl    Disk_Exp_Wrt    Disk Controller Expansion Write
  543.     Page    +
  544. ;******************************************************************************
  545. ;
  546. ;    Disk_Exp_Wrt(Effective_Address)
  547. ;
  548. ;        Return to the caller (Area is NOT writable)
  549. ;
  550. ;    Registers on Entry:
  551. ;
  552. ;        AL    - Memory value
  553. ;        DS:DI - 65C02 Effective address
  554. ;
  555. ;    Registers on Exit:
  556. ;
  557. ;        None
  558. ;
  559. ;******************************************************************************
  560.         Even            ; Force procedure to even address
  561. Disk_Exp_Wrt    Proc    Near        ; Disk ctrl. expansion write procedure
  562.     ret                ; Return to the caller
  563. Disk_Exp_Wrt    Endp            ; End of the Disk_Exp_Wrt procedure
  564.     Subttl    No_Operation    Disk Controller No Operation Routine
  565.     Page    +
  566. ;******************************************************************************
  567. ;
  568. ;    No_Operation(RAM_Space, Disk_Segment)
  569. ;
  570. ;        Get currently selected disk drive (A or B)
  571. ;        Return to the caller (With current phase value)
  572. ;
  573. ;    Registers on Entry:
  574. ;
  575. ;        DS    - 65C02 RAM space
  576. ;        ES    - Disk controller segment
  577. ;
  578. ;    Registers on Exit:
  579. ;
  580. ;        AL    - Current disk phase
  581. ;        AH    - Destroyed
  582. ;        BX    - Destroyed
  583. ;
  584. ;******************************************************************************
  585.         Even            ; Force procedure to even address
  586. No_Operation    Proc    Near        ; No operation procedure
  587.     mov    bx,es:[Disk_Current]    ; Get the currently selected drive
  588.     mov    al,es:[bx.Disk_Curr]    ; Get the current disk phase value
  589.     ret                ; Return to the caller
  590. No_Operation    Endp            ; End of the No_Operation procedure
  591.     Subttl    Disk_Phase    Disk Controller Phase Routine
  592.     Page    +
  593. ;******************************************************************************
  594. ;
  595. ;    Disk_Phase(RAM_Space, Disk_Segment, Control_Index, Slot_Index)
  596. ;
  597. ;        Get the new phase value (Control_Index / 2)
  598. ;        Get currently selected disk drive (A or B)
  599. ;        Compute change between last and current phase
  600. ;        Update the last phase value
  601. ;        If phase change made (Change <> 0)
  602. ;            If the track buffer is valid
  603. ;                If this track has been modified
  604. ;                    Call routine to write this track
  605. ;                Endif for track modified
  606. ;            Endif for track buffer valid
  607. ;            If change is positive (Step up)
  608. ;                Setup for phase increment
  609. ;            Else change is negative (Step down)
  610. ;                Setup for phase decrement
  611. ;            Endif for phase setup
  612. ;            Update the current phase value
  613. ;            If track value has changed
  614. ;                Reset track buffer valid flag
  615. ;            Endif for track value
  616. ;        Endif for phase change
  617. ;        Return to the caller (With current phase value)
  618. ;
  619. ;    Registers on Entry:
  620. ;
  621. ;        BX    - Control bits index (Control bits * 2)
  622. ;        BP    - Slot index (Slot number * 2)
  623. ;        DS    - 65C02 RAM space
  624. ;        ES    - Disk controller segment
  625. ;
  626. ;    Registers on Exit:
  627. ;
  628. ;        AL    - Current disk phase
  629. ;        AH    - Destroyed
  630. ;        BX    - Destroyed
  631. ;
  632. ;******************************************************************************
  633.         Even            ; Force procedure to even address
  634. Disk_Phase    Proc    Near        ; Disk phase procedure
  635.     mov    ax,bx            ; Get the control index value
  636.     shr    ax,1            ; Get the new phase value
  637.     mov    bx,es:[Disk_Current]    ; Get the currently selected drive
  638.     mov    ah,al            ; Move copy of new phase to AH
  639.     sub    ah,es:[bx.Disk_Last]    ; Compute the phase change value
  640.     mov    es:[bx.Disk_Last],al    ; Update the last phase value
  641.     mov    al,PHASE_INCREMENT    ; Default to a phase increment
  642.     jz    Phase_Exit        ; Jump if no phase change
  643.     jnc    Wrap_Check        ; Jump if positive phase change
  644.     mov    al,PHASE_DECREMENT    ; Setup for a phase decrement
  645.     not    ah            ; Compute the
  646.     inc    ah            ;          positive phase change
  647. Wrap_Check:
  648.     cmp    ah,PHASE_WRAP        ; Check for a phase wrap-around
  649.     jc    Track_Check        ; Jump if phase did NOT wrap around
  650.     not    al            ; Toggle the phase
  651.     inc    al            ;           increment value
  652. Track_Check:
  653.     test    es:[bx.Disk_Flag],BUFFER_VALID
  654.     jz    Phase_Update        ; Jump if buffer is invalid
  655.     test    es:[bx.Disk_Flag],TRACK_MODIFIED
  656.     jz    Phase_Update        ; Jump if track was NOT modified
  657.     call    Write_Track        ; Call routine to write this track
  658. Phase_Update:
  659.     add    al,es:[bx.Disk_Curr]    ; Compute the new disk phase value
  660.     cmp    al,PHASE_MAX        ; Check against phase maximum
  661.     jnc    Phase_Exit        ; Jump if new phase value is illegal
  662.     mov    ah,es:[bx.Disk_Curr]    ; Get the current disk phase value
  663.     mov    es:[bx.Disk_Curr],al    ; Update the disk phase value
  664.     and    ah,TRACK_MASK        ; Compute the current track phase value
  665.     cmp    ah,al            ; Check against current phase value
  666.     je    Phase_Exit        ; Jump if still on the same track
  667.     and    es:[bx.Disk_Flag],Not BUFFER_VALID
  668. Phase_Exit:
  669.     mov    al,es:[bx.Disk_Curr]    ; Get the current disk phase value
  670.     ret                ; Return to the caller
  671. Disk_Phase    Endp            ; End of the Disk_Phase procedure
  672.     Subttl    Disk_Off    Disk Controller Motor Off Routine
  673.     Page    +
  674. ;******************************************************************************
  675. ;
  676. ;    Disk_Off(RAM_Space, Disk_Segment, Control_Index, Slot_Index)
  677. ;
  678. ;        Set drive motor A status to off
  679. ;        If the track buffer is valid
  680. ;            If this track has been modified
  681. ;                Call routine to write this track
  682. ;            Endif for track modified
  683. ;        Endif for track buffer valid
  684. ;        Set drive motor B status to off
  685. ;        If the track buffer is valid
  686. ;            If this track has been modified
  687. ;                Call routine to write this track
  688. ;            Endif for track modified
  689. ;        Endif for track buffer valid
  690. ;        Return to the caller (With currently selected drive)
  691. ;
  692. ;    Registers on Entry:
  693. ;
  694. ;        BX    - Control bits index (Control bits * 2)
  695. ;        BP    - Slot index (Slot number * 2)
  696. ;        DS    - 65C02 RAM space
  697. ;        ES    - Disk controller segment
  698. ;
  699. ;    Registers on Exit:
  700. ;
  701. ;        AL    - Current drive selected
  702. ;        AH    - Destroyed
  703. ;        BX    - Destroyed
  704. ;
  705. ;******************************************************************************
  706.         Even            ; Force procedure to even address
  707. Disk_Off    Proc    Near        ; Disk motor off procedure
  708.     mov    bx,Disk_Drive_A     ; Get drive A structure pointer
  709.     and    es:[bx.Disk_Flag],Not MOTOR_ON
  710.     test    es:[bx.Disk_Flag],BUFFER_VALID
  711.     jz    B_Off            ; Jump if track buffer is invalid
  712.     test    es:[bx.Disk_Flag],TRACK_MODIFIED
  713.     jz    B_Off            ; Jump if track has NOT been modified
  714.     call    Write_Track        ; Call routine to write this track
  715. B_Off:
  716.     mov    bx,Disk_Drive_B     ; Get drive B structure pointer
  717.     and    es:[bx.Disk_Flag],Not MOTOR_ON
  718.     test    es:[bx.Disk_Flag],BUFFER_VALID
  719.     jz    Off_Done        ; Jump if track buffer is invalid
  720.     test    es:[bx.Disk_Flag],TRACK_MODIFIED
  721.     jz    Off_Done        ; Jump if track has NOT been modified
  722.     call    Write_Track        ; Call routine to write this track
  723. Off_Done:
  724.     mov    bx,es:[Disk_Current]    ; Get the currently selected drive
  725.     mov    al,DRIVE_A        ; Default to drive A selected
  726.     cmp    bx,Disk_Drive_A     ; Check for disk drive B selected
  727.     je    Off_Exit        ; Jump if drive B is NOT selected
  728.     mov    al,DRIVE_B        ; Indicate drive B selected
  729. Off_Exit:
  730.     ret                ; Return to the caller
  731. Disk_Off    Endp            ; End of the Disk_Off procedure
  732.     Subttl    Disk_On     Disk Controller Motor On Routine
  733.     Page    +
  734. ;******************************************************************************
  735. ;
  736. ;    Disk_On(RAM_Space, Disk_Segment, Control_Index, Slot_Index)
  737. ;
  738. ;        Set drive motor A status to on
  739. ;        Set drive motor B status to on
  740. ;        Return to the caller (With currently selected drive)
  741. ;
  742. ;    Registers on Entry:
  743. ;
  744. ;        BX    - Control bits index (Control bits * 2)
  745. ;        BP    - Slot index (Slot number * 2)
  746. ;        DS    - 65C02 RAM space
  747. ;        ES    - Disk controller segment
  748. ;
  749. ;    Registers on Exit:
  750. ;
  751. ;        AL    - Current drive selected
  752. ;        AH    - Destroyed
  753. ;        BX    - Destroyed
  754. ;
  755. ;******************************************************************************
  756.         Even            ; Force procedure to even address
  757. Disk_On     Proc    Near        ; Disk motor on procedure
  758.     mov    bx,Disk_Drive_A     ; Get drive A structure pointer
  759.     or    es:[bx.Disk_Flag],MOTOR_ON
  760.     mov    bx,Disk_Drive_B     ; Get drive B structure pointer
  761.     or    es:[bx.Disk_Flag],MOTOR_ON
  762.     mov    bx,es:[Disk_Current]    ; Get the currently selected drive
  763.     mov    al,DRIVE_A        ; Default to drive A selected
  764.     cmp    bx,Disk_Drive_A     ; Check for disk drive B selected
  765.     je    On_Exit         ; Jump if drive B is NOT selected
  766.     mov    al,DRIVE_B        ; Indicate drive B selected
  767. On_Exit:
  768.     ret                ; Return to the caller
  769. Disk_On     Endp            ; End of the Disk_On procedure
  770.     Subttl    Select_A    Disk Controller Select Drive A Routine
  771.     Page    +
  772. ;******************************************************************************
  773. ;
  774. ;    Select_A(RAM_Space, Disk_Segment, Control_Index, Slot_Index)
  775. ;
  776. ;        Set current drive to drive A
  777. ;        Return to the caller (With currently selected drive) [A]
  778. ;
  779. ;    Registers on Entry:
  780. ;
  781. ;        BX    - Control bits index (Control bits * 2)
  782. ;        BP    - Slot index (Slot number * 2)
  783. ;        DS    - 65C02 RAM space
  784. ;        ES    - Disk controller segment
  785. ;
  786. ;    Registers on Exit:
  787. ;
  788. ;        AL    - Current drive selected (A)
  789. ;        AH    - Destroyed
  790. ;        BX    - Destroyed
  791. ;
  792. ;******************************************************************************
  793.         Even            ; Force procedure to even address
  794. Select_A    Proc    Near        ; Select drive A procedure
  795.     mov    es:[Disk_Current],Disk_Drive_A
  796.     mov    al,DRIVE_A        ; Indicate drive A selected
  797.     ret                ; Return to the caller
  798. Select_A    Endp            ; End of the Select_A procedure
  799.     Subttl    Select_B    Disk Controller Select Drive B Routine
  800.     Page    +
  801. ;******************************************************************************
  802. ;
  803. ;    Select_B(RAM_Space, Disk_Segment, Control_Index, Slot_Index)
  804. ;
  805. ;        Set current drive to drive B
  806. ;        Return to the caller (With currently selected drive) [B]
  807. ;
  808. ;    Registers on Entry:
  809. ;
  810. ;        BX    - Control bits index (Control bits * 2)
  811. ;        BP    - Slot index (Slot number * 2)
  812. ;        DS    - 65C02 RAM space
  813. ;        ES    - Disk controller segment
  814. ;
  815. ;    Registers on Exit:
  816. ;
  817. ;        AL    - Current drive selected (B)
  818. ;        AH    - Destroyed
  819. ;        BX    - Destroyed
  820. ;
  821. ;******************************************************************************
  822.         Even            ; Force procedure to even address
  823. Select_B    Proc    Near        ; Select drive B procedure
  824.     mov    es:[Disk_Current],Disk_Drive_B
  825.     mov    al,DRIVE_B        ; Indicate drive B selected
  826.     ret                ; Return to the caller
  827. Select_B    Endp            ; End of the Select_B procedure
  828.     Subttl    Data_Strobe    Disk Controller Data Strobe Routine
  829.     Page    +
  830. ;******************************************************************************
  831. ;
  832. ;    Data_Strobe(RAM_Space, Disk_Segment, Control_Index, Slot_Index)
  833. ;
  834. ;        Get currently selected disk drive (A or B)
  835. ;        If in output mode
  836. ;            If disk is present
  837. ;                Call routine to write a byte
  838. ;                Set the buffer valid flag bit
  839. ;                Set the track modified flag bit
  840. ;            Endif for disk present
  841. ;        Else in input mode
  842. ;            If disk is present
  843. ;                If track buffer is invalid
  844. ;                    Call routine to read the track
  845. ;                Endif for track buffer invalid
  846. ;                Call routine to read a byte
  847. ;            Endif for disk present
  848. ;        Endif for controller mode
  849. ;        Return to the caller
  850. ;
  851. ;    Registers on Entry:
  852. ;
  853. ;        BX    - Control bits index (Control bits * 2)
  854. ;        BP    - Slot index (Slot number * 2)
  855. ;        DS    - 65C02 RAM space
  856. ;        ES    - Disk controller segment
  857. ;
  858. ;    Registers on Exit:
  859. ;
  860. ;        AL    - Data value (If read)
  861. ;        AH    - Destroyed
  862. ;        BX    - Destroyed
  863. ;        BP    - Destroyed
  864. ;
  865. ;******************************************************************************
  866.         Even            ; Force procedure to even address
  867. Data_Strobe    Proc    Near        ; Disk data strobe procedure
  868.     not    al            ; Fake the disk ready (Data changing)
  869.     mov    bx,es:[Disk_Current]    ; Get the currently selected drive
  870.     mov    ah,es:[bx.Disk_Flag]    ; Get the disk drive flag byte
  871.     test    ah,OUTPUT_MODE        ; Check for controller in output mode
  872.     jz    Read_Mode        ; Jump if controller in input mode
  873. Write_Mode:
  874.     test    ah,DISK_PRESENT     ; Check for a disk present
  875.     jz    Strobe_Exit        ; Jump if no disk is installed
  876.     call    Write_Byte        ; Call routine to write a byte
  877.     or    es:[bx.Disk_Flag],TRACK_MODIFIED + BUFFER_VALID
  878.     jmp    Short Strobe_Exit    ; Go return to the caller
  879. Read_Mode:
  880.     test    ah,DISK_PRESENT     ; Check for a disk present
  881.     jz    Strobe_Exit        ; Jump if no disk is installed
  882.     test    ah,BUFFER_VALID     ; Check for track buffer valid
  883.     jnz    Data_Read        ; Jump if buffer is valid
  884.     call    Read_Track        ; Call routine to read a track
  885. Data_Read:
  886.     call    Read_Byte        ; Call routine to read a byte
  887. Strobe_Exit:
  888.     ret                ; Return to the caller
  889. Data_Strobe    Endp            ; End of the Data_Strobe procedure
  890.     Subttl    Load_Latch    Disk Controller Load Latch Routine
  891.     Page    +
  892. ;******************************************************************************
  893. ;
  894. ;    Load_Latch(RAM_Space, Disk_Segment, Control_Index, Slot_Index, Data)
  895. ;
  896. ;        Get currently selected disk drive (A or B)
  897. ;        Save data value to the disk latch
  898. ;        Return to the caller (With currently selected drive)
  899. ;
  900. ;    Registers on Entry:
  901. ;
  902. ;        AL    - Data value
  903. ;        BX    - Control bits index (Control bits * 2)
  904. ;        BP    - Slot index (Slot number * 2)
  905. ;        DS    - 65C02 RAM space
  906. ;        ES    - Disk controller segment
  907. ;
  908. ;    Registers on Exit:
  909. ;
  910. ;        AL    - Current drive selected
  911. ;        AH    - Destroyed
  912. ;        BX    - Destroyed
  913. ;
  914. ;******************************************************************************
  915.         Even            ; Force procedure to even address
  916. Load_Latch    Proc    Near        ; Load data latch procedure
  917.     mov    bx,es:[Disk_Current]    ; Get the currently selected drive
  918.     mov    es:[bx.Disk_Latch],al    ; Save the disk data latch value
  919.     mov    al,DRIVE_A        ; Default to drive A selected
  920.     cmp    bx,Disk_Drive_A     ; Check for disk drive B selected
  921.     je    Latch_Exit        ; Jump if drive B is NOT selected
  922.     mov    al,DRIVE_B        ; Indicate drive B selected
  923. Latch_Exit:
  924.     ret                ; Return to the caller
  925. Load_Latch    Endp            ; End of the Load_Latch procedure
  926.     Subttl    Prepare_Input    Disk Controller Prepare Input Routine
  927.     Page    +
  928. ;******************************************************************************
  929. ;
  930. ;    Prepare_Input(RAM_Space, Disk_Segment, Control_Index, Slot_Index)
  931. ;
  932. ;        Set drive A controller mode to input
  933. ;        Set drive B controller mode to input
  934. ;        Get currently selected disk drive (A or B)
  935. ;        Get disk drive write protect status
  936. ;        Return to the caller (With write protect status)
  937. ;
  938. ;    Registers on Entry:
  939. ;
  940. ;        BX    - Control bits index (Control bits * 2)
  941. ;        BP    - Slot index (Slot number * 2)
  942. ;        DS    - 65C02 RAM space
  943. ;        ES    - Disk controller segment
  944. ;
  945. ;    Registers on Exit:
  946. ;
  947. ;        AL    - Write protect status
  948. ;        AH    - Destroyed
  949. ;        BX    - Destroyed
  950. ;
  951. ;******************************************************************************
  952.         Even            ; Force procedure to even address
  953. Prepare_Input    Proc    Near        ; Prepare disk input procedure
  954.     and    es:[Disk_Drive_A.Disk_Flag],Not OUTPUT_MODE
  955.     and    es:[Disk_Drive_A.Disk_Flag],Not OUTPUT_MODE
  956.     mov    bx,es:[Disk_Current]    ; Get the currently selected drive
  957.     xor    al,al            ; Default to drive NOT write protected
  958.     test    es:[bx.Disk_Flag],WRITE_PROTECT
  959.     jz    Input_Exit        ; Jump if disk is NOT write protected
  960.     or    al,DISK_PROTECT     ; Set the disk write protected flag
  961. Input_Exit:
  962.     ret                ; Return to the caller
  963. Prepare_Input    Endp            ; End of the Prepare_Input procedure
  964.     Subttl    Prepare_Output    Disk Controller Prepare Output Routine
  965.     Page    +
  966. ;******************************************************************************
  967. ;
  968. ;    Prepare_Output(RAM_Space, Disk_Segment, Control_Index, Slot_Index)
  969. ;
  970. ;        Set drive A controller mode to output
  971. ;        Set drive B controller mode to output
  972. ;        Get currently selected disk drive (A or B)
  973. ;        Return to the caller (With currently selected drive)
  974. ;
  975. ;    Registers on Entry:
  976. ;
  977. ;        BX    - Control bits index (Control bits * 2)
  978. ;        BP    - Slot index (Slot number * 2)
  979. ;        DS    - 65C02 RAM space
  980. ;        ES    - Disk controller segment
  981. ;
  982. ;    Registers on Exit:
  983. ;
  984. ;        AL    - Current drive selected
  985. ;        AH    - Destroyed
  986. ;        BX    - Destroyed
  987. ;
  988. ;******************************************************************************
  989.         Even            ; Force procedure to even address
  990. Prepare_Output    Proc    Near        ; Prepare disk output procedure
  991.     or    es:[Disk_Drive_A.Disk_Flag],OUTPUT_MODE
  992.     or    es:[Disk_Drive_A.Disk_Flag],OUTPUT_MODE
  993.     mov    bx,es:[Disk_Current]    ; Get the currently selected drive
  994.     mov    al,DRIVE_A        ; Default to drive A selected
  995.     cmp    bx,Disk_Drive_A     ; Check for disk drive B selected
  996.     je    Output_Exit        ; Jump if drive B is NOT selected
  997.     mov    al,DRIVE_B        ; Indicate drive B selected
  998. Output_Exit:
  999.     ret                ; Return to the caller
  1000. Prepare_Output    Endp            ; End of the Prepare_Output procedure
  1001.     Subttl    Read_Track    Disk Controller Read Track Routine
  1002.     Page    +
  1003. ;******************************************************************************
  1004. ;
  1005. ;    Read_Track(Drive_Structure)
  1006. ;
  1007. ;        Save the required registers
  1008. ;        Get the disk file handle
  1009. ;        Get the current phase value
  1010. ;        Compute the current track (Phase / 2)
  1011. ;        Try to seek to the correct position
  1012. ;        If no errors seeking to the correct position
  1013. ;            Get the track buffer segment
  1014. ;            Get the track buffer size (13/16 Sector disk)
  1015. ;            Try to read the requested track
  1016. ;            If no errors reading the requested track
  1017. ;                Call routine to encrypt the track
  1018. ;            Endif for reading the track
  1019. ;        Endif for seeking to track
  1020. ;        Set the track buffer valid flag
  1021. ;        Restore the required registers
  1022. ;        Return to the caller
  1023. ;
  1024. ;    Registers on Entry:
  1025. ;
  1026. ;        ES:BX - Disk drive structure pointer
  1027. ;
  1028. ;    Registers on Exit:
  1029. ;
  1030. ;        AX    - Destroyed
  1031. ;        BP    - Destroyed
  1032. ;
  1033. ;******************************************************************************
  1034.         Even            ; Force procedure to even address
  1035. Read_Track    Proc    Near        ; Disk read track procedure
  1036.     Save    cx,dx,ds        ; Save the required registers
  1037.     mov    bp,es:[bx.Disk_Handle]    ; Get the disk file handle
  1038.     xchg    bx,bp            ; Move file handle to BX register
  1039.     mov    al,es:[bp.Disk_Curr]    ; Get the current disk phase value
  1040.     shr    al,1            ; Convert phase to track value (/ 2)
  1041.     xor    ah,ah            ; Convert track value to full word
  1042.     mul    es:[bp.Disk_Track]    ; Compute the track offset value (DX:AX)
  1043.     mov    cx,dx            ; Move track offset
  1044.     mov    dx,ax            ;            to CX:DX reg. pair
  1045.     mov    ah,SEEK_FILE        ; Get the seek file function code
  1046.     mov    al,ABSOLUTE        ; Get the absolute seek type code
  1047.     int    DOS            ; Seek to correct position
  1048.     jc    Read_Exit        ; Jump if error during seek operation
  1049.     mov    ds,cs:[Track_Save]    ; Get the track buffer segment
  1050.     xor    dx,dx            ; Zero the offset value
  1051.     mov    cx,es:[bp.Disk_Track]    ; Get the track buffer size (Bytes)
  1052.     mov    ah,READ_FILE        ; Get read file function code
  1053.     int    DOS            ; Try to read the desired track
  1054.     jc    Read_Exit        ; Jump if errors reading track
  1055.     call    Encrypt_Track        ; Call routine to encrypt the track
  1056. Read_Exit:
  1057.     xchg    bx,bp            ; Restore the drive structure pointer
  1058.     or    es:[bx.Disk_Flag],BUFFER_VALID
  1059.     Restore cx,dx,ds        ; Restore the required registers
  1060.     ret                ; Return to the caller
  1061. Read_Track    Endp            ; End of the Read_Track procedure
  1062.     Subttl    Write_Track    Disk Controller Write Track Routine
  1063.     Page    +
  1064. ;******************************************************************************
  1065. ;
  1066. ;    Write_Track(Drive_Structure)
  1067. ;
  1068. ;        Save the required registers
  1069. ;        Get pointer to track buffer area
  1070. ;        Call routine to decrypt the track
  1071. ;        Get the disk file handle
  1072. ;        Get the current phase value
  1073. ;        Compute the current track (Phase / 2)
  1074. ;        Try to seek to the correct position
  1075. ;        If no errors seeking to the correct position
  1076. ;            Get the track buffer size (13/16 Sector disk)
  1077. ;            Try to write the requested track
  1078. ;        Endif for seeking to track
  1079. ;        Restore the required registers
  1080. ;        Clear the track modified flag
  1081. ;        Return to the caller
  1082. ;
  1083. ;    Registers on Entry:
  1084. ;
  1085. ;        ES:BX - Disk drive structure pointer
  1086. ;
  1087. ;    Registers on Exit:
  1088. ;
  1089. ;        BP    - Destroyed
  1090. ;
  1091. ;******************************************************************************
  1092.         Even            ; Force procedure to even address
  1093. Write_Track    Proc    Near        ; Disk write track procedure
  1094.     Save    ax,cx,dx,ds        ; Save the required registers
  1095.     mov    ds,cs:[Track_Save]    ; Get the track buffer segment
  1096.     xor    dx,dx            ; Zero the offset value
  1097.     mov    bp,es:[bx.Disk_Handle]    ; Get the disk file handle
  1098.     xchg    bx,bp            ; Move file handle to BX register
  1099.     call    Decrypt_Track        ; Call routine to decrypt the track
  1100.     mov    al,es:[bp.Disk_Curr]    ; Get the current disk phase value
  1101.     shr    al,1            ; Convert phase to track value (/ 2)
  1102.     xor    ah,ah            ; Convert track value to full word
  1103.     mul    es:[bp.Disk_Track]    ; Compute the track offset value (DX:AX)
  1104.     mov    cx,dx            ; Move track offset
  1105.     mov    dx,ax            ;            to CX:DX reg. pair
  1106.     mov    ah,SEEK_FILE        ; Get the seek file function code
  1107.     mov    al,ABSOLUTE        ; Get the absolute seek type code
  1108.     int    DOS            ; Seek to correct position
  1109.     jc    Write_Exit        ; Jump if error during seek operation
  1110.     mov    cx,es:[bp.Disk_Track]    ; Get the track buffer size (Bytes)
  1111.     xor    dx,dx            ; Zero the track buffer offset value
  1112.     mov    ah,WRITE_FILE        ; Get write file function code
  1113.     int    DOS            ; Try to write the desired track
  1114. Write_Exit:
  1115.     xchg    bx,bp            ; Restore the drive structure pointer
  1116.     and    es:[bx.Disk_Flag],Not TRACK_MODIFIED
  1117.     Restore ax,cx,dx,ds        ; Restore the required registers
  1118.     ret                ; Return to the caller
  1119. Write_Track    Endp            ; End of the Write_Track procedure
  1120.     Subttl    Encrypt_Track    Disk Controller Encrypt Track Routine
  1121.     Page    +
  1122. ;******************************************************************************
  1123. ;
  1124. ;    Encrypt_Track(Track_Buffer, Drive_Structure)
  1125. ;
  1126. ;        Save the required registers
  1127. ;        Get pointer to track data area
  1128. ;        Fill in the gap 1 area
  1129. ;        Get the track number
  1130. ;        Get pointer to sector skew table
  1131. ;        Initialize the sector count (13/16)
  1132. ;        While sector count > 0
  1133. ;            Get the correct sector number
  1134. ;            Get pointer to sector data
  1135. ;            Call routine to encrypt the sector
  1136. ;            Decrement the sector count
  1137. ;        Endwhile for sector count
  1138. ;        Restore the required registers
  1139. ;        Return to the caller
  1140. ;
  1141. ;    Registers on Entry:
  1142. ;
  1143. ;        DS:DX - Pointer to track buffer area
  1144. ;        ES:BP - Disk drive structure pointer
  1145. ;
  1146. ;    Registers on Exit:
  1147. ;
  1148. ;        AX    - Destroyed
  1149. ;
  1150. ;******************************************************************************
  1151.         Even            ; Force procedure to even address
  1152. Encrypt_Track    Proc    Near        ; Encrypt track procedure
  1153.     Save    bx,cx,si,di        ; Save the required registers
  1154.     lea    di,es:[bp.Disk_Buffer]    ; Get pointer to disk track buffer
  1155.     Fill    GAP_1, SELF_SYNC    ; Fill in gap 1 area with self sync's
  1156.     mov    ah,es:[bp.Disk_Curr]    ; Get the current disk phase
  1157.     shr    ah,1            ; Convert current phase to track number
  1158.     lea    bx,cs:[Skew_Table]    ; Get pointer to sector skew table
  1159.     mov    cl,es:[bp.Disk_Sector]    ; Get the number of sectors per. track
  1160.     mov    ch,cl            ; Move copy of sectors/track to CH
  1161. Encrypt_Loop:
  1162.     mov    al,ch            ; Get the number of sectors/track
  1163.     sub    al,cl            ; Compute the current sector number
  1164.     xlat    cs:[bx]         ; Get the actual sector number
  1165.     xchg    al,ah            ; Move sector number into AH register
  1166.     mov    si,ax            ; Move sector pointer into SI
  1167.     and    si,SECTOR_MASK        ; Mask off all but the sector pointer
  1168.     xchg    al,ah            ; Restore the track/sector order
  1169.     mov    al,ch            ; Get the number of sectors/track
  1170.     sub    al,cl            ; Compute the current sector number
  1171.     call    Encrypt_Sector        ; Call routine to encrypt this sector
  1172.     dec    cl            ; Decrement the sector counter
  1173.     jnz    Encrypt_Loop        ; Jump if more sectors to encrypt
  1174. Encrypt_Exit:
  1175.     Restore bx,cx,si,di        ; Restore the required registers
  1176.     ret                ; Return to the caller
  1177. Encrypt_Track    Endp            ; End of the Encrypt_Track procedure
  1178.     Subttl    Decrypt_Track    Disk Controller Decrypt Track Routine
  1179.     Page    +
  1180. ;******************************************************************************
  1181. ;
  1182. ;    Decrypt_Track(Track_Buffer, Drive_Structure)
  1183. ;
  1184. ;        Save the required registers
  1185. ;        Get pointer to track data area
  1186. ;        While pointer < track_limit
  1187. ;            Search for a address mark
  1188. ;            If address mark found
  1189. ;                Search for a data mark
  1190. ;                If data mark found
  1191. ;                    Compute address of sector (Skew table)
  1192. ;                    Call routine to decrypt sector
  1193. ;                Endif for data mark
  1194. ;            Endif for address mark
  1195. ;            Increment the pointer
  1196. ;        Endwhile
  1197. ;        Restore the required registers
  1198. ;        Return to the caller
  1199. ;
  1200. ;    Registers on Entry:
  1201. ;
  1202. ;        DS:DX - Pointer to track buffer area
  1203. ;        ES:BP - Disk drive structure pointer
  1204. ;
  1205. ;    Registers on Exit:
  1206. ;
  1207. ;        AX    - Destroyed
  1208. ;
  1209. ;******************************************************************************
  1210.         Even            ; Force procedure to even address
  1211. Decrypt_Track    Proc    Near        ; Decrypt track procedure
  1212.     Save    bx,cx,si,di        ; Save the required registers
  1213.     lea    bx,es:[bp.Disk_Buffer]    ; Get pointer to disk buffer
  1214.     xor    di,di            ; Zero the buffer offset (Start)
  1215. Address_Loop:
  1216.     cmp    Byte Ptr es:[bx+di],PRO_ADDR_1
  1217.     jne    Address_Byte        ; Jump if NOT address prologue byte 1
  1218.     inc    di            ; Increment the buffer pointer
  1219.     cmp    Byte Ptr es:[bx+di],PRO_ADDR_2
  1220.     jne    Next_Address        ; Jump if NOT address prologue byte 2
  1221.     inc    di            ; Increment the buffer pointer
  1222.     cmp    Byte Ptr es:[bx+di],PRO_ADDR_3
  1223.     jne    Next_Address        ; Jump if NOT address prologue byte 3
  1224.     inc    di            ; Increment the buffer pointer
  1225.     add    di,Track - Volume    ; Increment past disk volume to track
  1226.     mov    ax,es:[bx+di]        ; Get the encrypted track number
  1227.     Decrypt_Byte            ; Decrypt the track value
  1228.     mov    ch,al            ; Save track number in CH register
  1229.     inc    di            ; Increment past
  1230.     inc    di            ;         encrypted track number
  1231.     mov    ax,es:[bx+di]        ; Get the encrypted sector number
  1232.     Decrypt_Byte            ; Decrypt the sector number
  1233.     mov    cl,al            ; Save sector number in CL register
  1234.     inc    di            ; Increment past
  1235.     inc    di            ;         encrypted sector number
  1236.     jmp    Short Data_Loop     ; Go search for matching data mark
  1237. Address_Byte:
  1238.     inc    di            ; Increment the buffer pointer
  1239. Next_Address:
  1240.     cmp    di,es:[bp.Disk_Limit]    ; Check pointer against track limit
  1241.     jb    Address_Loop        ; Jump if more data in the buffer
  1242.     jmp    Short Decrypt_Exit    ; Go return to the caller
  1243. Data_Loop:
  1244.     cmp    Byte Ptr es:[bx+di],PRO_DATA_1
  1245.     jne    Data_Byte        ; Jump if NOT data prologue byte 1
  1246.     inc    di            ; Increment the buffer pointer
  1247.     cmp    Byte Ptr es:[bx+di],PRO_DATA_2
  1248.     jne    Next_Data        ; Jump if NOT data prologue byte 2
  1249.     inc    di            ; Increment the buffer pointer
  1250.     cmp    Byte Ptr es:[bx+di],PRO_DATA_3
  1251.     jne    Next_Data        ; Jump if NOT data prologue byte 3
  1252.     inc    di            ; Increment the buffer pointer
  1253.     mov    al,cl            ; Get the sector number in AL
  1254.     xor    ah,ah            ; Convert sector number to full word
  1255.     xchg    ax,bx            ; Put sector number into BX
  1256.     mov    bl,cs:[bx + Skew_Table] ; Get the actual sector number
  1257.     xchg    ax,bx            ; Put actual sector number into AX
  1258.     xchg    al,ah            ; Compute actual sector address (* 256)
  1259.     mov    si,ax            ; Move sector address to SI register
  1260.     call    Decrypt_Sector        ; Call routine to decrypt the sector
  1261.     jmp    Short Next_Address    ; Go search for next address mark
  1262. Data_Byte:
  1263.     inc    di            ; Increment the buffer pointer
  1264. Next_Data:
  1265.     cmp    di,es:[bp.Disk_Limit]    ; Check pointer against track limit
  1266.     jb    Data_Loop        ; Jump if more data in the buffer
  1267. Decrypt_Exit:
  1268.     Restore bx,cx,si,di        ; Restore the required registers
  1269.     ret                ; Return to the caller
  1270. Decrypt_Track    Endp            ; End of the Decrypt_Track procedure
  1271.     Subttl    Encrypt_Sector    Disk Controller Encrypt Sector Routine
  1272.     Page    +
  1273. ;******************************************************************************
  1274. ;
  1275. ;    Encrypt_Sector(Track, Sector, Sector_Area, Drive_Structure, Buffer_Area)
  1276. ;
  1277. ;        Save the required registers
  1278. ;        Store address mark prologue in buffer
  1279. ;        Encrypt disk volume and store in buffer
  1280. ;        Encrypt track number and store in buffer
  1281. ;        Encrypt sector number and store in buffer
  1282. ;        Compute address mark checksum (Volume, Track, and Sector)
  1283. ;        Encrypt checksum and store in buffer
  1284. ;        Store address mark epilogue in buffer
  1285. ;        Fill in the gap 2 area
  1286. ;        Store data mark prologue in buffer
  1287. ;        Call routine to pre-nibblize the sector data
  1288. ;        Setup encryption table based on disk type
  1289. ;        Set byte count to sector size
  1290. ;        While byte count > 0
  1291. ;            Encrypt data byte from pre-nibble buffer
  1292. ;            Store encrypted byte in buffer
  1293. ;            Decrement the byte counter
  1294. ;        Endwhile
  1295. ;        Encrypt checksum and store in buffer
  1296. ;        Store data mark epilogue in buffer
  1297. ;        Fill in the gap 3 area
  1298. ;        Restore the required registers
  1299. ;        Return to the caller
  1300. ;
  1301. ;    Registers on Entry:
  1302. ;
  1303. ;        AH    - Track number
  1304. ;        AL    - Sector number
  1305. ;        DS:SI - Pointer to sector area
  1306. ;        ES:DI - Pointer to buffer area
  1307. ;        ES:BP - Disk drive structure pointer
  1308. ;
  1309. ;    Registers on Exit:
  1310. ;
  1311. ;        SI    - Destroyed
  1312. ;        DI    - Updated to point to next sector
  1313. ;
  1314. ;******************************************************************************
  1315.         Even            ; Force procedure to even address
  1316. Encrypt_Sector    Proc    Near        ; Encrypt sector procedure
  1317.     Save    ax,bx,cx,ds        ; Save the required registers
  1318.     mov    bx,ax            ; Save track/sector number in BX
  1319.     mov    al,PRO_ADDR_1        ; Get address mark prologue byte 1
  1320.     stosb                ; Store progogue byte in buffer
  1321.     mov    al,PRO_ADDR_2        ; Get address mark prologue byte 2
  1322.     stosb                ; Store prologue byte in buffer
  1323.     mov    al,PRO_ADDR_3        ; Get address mark prologue byte 3
  1324.     stosb                ; Store prologue byte in buffer
  1325.     mov    al,DISK_VOLUME        ; Get the dummy disk volume number
  1326.     Encrypt_Byte            ; Encrypt the disk volume number
  1327.     stosw                ; Store the disk volume number
  1328.     mov    al,bh            ; Get the disk track number
  1329.     Encrypt_Byte            ; Encrypt the disk track number
  1330.     stosw                ; Store the disk track number
  1331.     mov    al,bl            ; Get the disk sector number
  1332.     Encrypt_Byte            ; Encrypt the disk sector number
  1333.     stosw                ; Store the disk sector number
  1334.     mov    al,DISK_VOLUME        ; Get disk volume to compute checksum
  1335.     xor    al,bh            ; Add track number to checksum
  1336.     xor    al,bl            ; Add sector number to checksum
  1337.     Encrypt_Byte            ; Encrypt the checksum value
  1338.     stosw                ; Store the checksum value
  1339.     mov    al,EPI_ADDR_1        ; Get address mark epilogue byte 1
  1340.     stosb                ; Store epilogue byte in buffer
  1341.     mov    al,EPI_ADDR_2        ; Get address mark epilogue byte 2
  1342.     stosb                ; Store epilogue byte in buffer
  1343.     mov    al,EPI_ADDR_3        ; Get address mark epilogue byte 3
  1344.     stosb                ; Store epilogue byte in buffer
  1345.     Fill    GAP_2, SELF_SYNC    ; Fill in gap 2 area with self sync's
  1346.     mov    al,PRO_DATA_1        ; Get data mark prologue byte 1
  1347.     stosb                ; Store progogue byte in buffer
  1348.     mov    al,PRO_DATA_2        ; Get data mark prologue byte 2
  1349.     stosb                ; Store prologue byte in buffer
  1350.     mov    al,PRO_DATA_3        ; Get data mark prologue byte 3
  1351.     stosb                ; Store prologue byte in buffer
  1352.     call    Pre_Nibble        ; Call routine to pre-nibblize sector
  1353.     mov    ds,cs:[Nibble_Save]    ; Get nibblization buffer segment
  1354.     lea    bx,cs:[Nibble_6_2]    ; Get 6 to 2 nibble encoding table
  1355.     mov    si,BREAK_6_2 - 1    ; Get 6 to 2 break point value - 1
  1356.     test    es:[bp.Disk_Flag],OLD_STYLE
  1357.     jz    Pre_Setup        ; Jump if a 16 sector type disk
  1358.     lea    bx,cs:[Nibble_5_3]    ; Get 5 to 3 nibble encoding table
  1359.     mov    si,BREAK_5_3 - 1    ; Get 5 to 3 break point value - 1
  1360. Pre_Setup:
  1361.     xor    al,al            ; Start checksum value with a zero
  1362.     mov    cx,NIBBLE_BREAK     ; Get nibble break point (Sector size)
  1363. Break_Loop:
  1364.     xor    al,ds:[si+NIBBLE_BREAK] ; Compute the next byte value
  1365.     xlat    cs:[bx]         ; Encode the byte value through table
  1366.     stosb                ; Store the byte in the track buffer
  1367.     mov    al,ds:[si+NIBBLE_BREAK] ; Get next byte for encoding
  1368.     dec    si            ; Decrement the index value
  1369.     jns    Break_Loop        ; Jump if more nibble break to process
  1370.     inc    si            ; Restore SI index to zero
  1371. Sector_Loop:
  1372.     xor    al,ds:[si]        ; Compute the next byte value
  1373.     xlat    cs:[bx]         ; Encode the byte value through table
  1374.     stosb                ; Store the byte in the track buffer
  1375.     mov    al,ds:[si]        ; Get next byte for encoding
  1376.     inc    si            ; Increment the index value
  1377.     loop    Sector_Loop        ; Loop till all sector data processed
  1378.     xlat    cs:[bx]         ; Encode the checksum byte value
  1379.     stosb                ; Store checksum byte value in buffer
  1380.     mov    al,EPI_DATA_1        ; Get data mark epilogue byte 1
  1381.     stosb                ; Store epilogue byte in buffer
  1382.     mov    al,EPI_DATA_2        ; Get data mark epilogue byte 2
  1383.     stosb                ; Store epilogue byte in buffer
  1384.     mov    al,EPI_DATA_3        ; Get data mark epilogue byte 3
  1385.     stosb                ; Store epilogue byte in buffer
  1386.     Fill    GAP_3, SELF_SYNC    ; Fill in gap 3 area with self sync's
  1387.     Restore ax,bx,cx,ds        ; Restore the required registers
  1388.     ret                ; Return to the caller
  1389. Encrypt_Sector    Endp            ; End of the Encrypt_Sector procedure
  1390.     Subttl    Decrypt_Sector    Disk Controller Decrypt Sector Routine
  1391.     Page    +
  1392. ;******************************************************************************
  1393. ;
  1394. ;    Decrypt_Sector(Sector_Area, Track_Buffer, Drive_Structure)
  1395. ;
  1396. ;        Save the required registers
  1397. ;        Setup decryption table based on disk type
  1398. ;        Set byte count to sector size
  1399. ;        While byte count > 0
  1400. ;            Decrypt data byte from track buffer
  1401. ;            Store decrypted byte in nibble buffer
  1402. ;            Decrement the byte counter
  1403. ;        Endwhile
  1404. ;        Call routine to post-nibblize sector
  1405. ;        Restore the required registers
  1406. ;        Return to the caller
  1407. ;
  1408. ;    Registers on Entry:
  1409. ;
  1410. ;        DS:SI - Pointer to sector area
  1411. ;        ES:BX - Pointer to buffer area
  1412. ;        ES:BP - Disk drive structure pointer
  1413. ;        DI    - Offset into buffer area
  1414. ;
  1415. ;    Registers on Exit:
  1416. ;
  1417. ;        SI    - Destroyed
  1418. ;
  1419. ;******************************************************************************
  1420.         Even            ; Force procedure to even address
  1421. Decrypt_Sector    Proc    Near        ; Decrypt sector procedure
  1422.     Save    ax,bx,cx,dx,di        ; Save the required registers
  1423.     add    bx,di            ; Compute actual track buffer offset
  1424.     Save    si,di,ds,es        ; Save the buffer pointers
  1425.     mov    si,bx            ; Setup track buffer offset value
  1426.     mov    ax,es            ; Get the track buffer segment
  1427.     mov    ds,ax            ; Set DS to the track buffer segment
  1428.     lea    dx,cs:[Decode_6_2]    ; Get 6 to 2 nibble decoding table
  1429.     mov    di,BREAK_6_2 - 1    ; Get 6 to 2 break point value - 1
  1430.     test    es:[bp.Disk_Flag],OLD_STYLE
  1431.     jz    Post_Setup        ; Jump if a 16 sector type disk
  1432.     lea    dx,cs:[Decode_5_3]    ; Get 5 to 3 nibble decoding table
  1433.     mov    di,BREAK_5_3 - 1    ; Get 5 to 3 break point value - 1
  1434. Post_Setup:
  1435.     xor    ah,ah            ; Start checksum value with a zero
  1436.     mov    cx,NIBBLE_BREAK     ; Get nibble break point (Sector size)
  1437.     mov    es,cs:[Nibble_Save]    ; Get nibblization buffer segment
  1438. Loop_Break:
  1439.     lodsb                ; Get the next data byte to decode
  1440.     and    al,DECODE_MASK        ; Mask off all but the decode bits
  1441.     xchg    bx,dx            ; Get the decoding table into BX
  1442.     xlat    cs:[bx]         ; Decode the byte value through table
  1443.     xchg    bx,dx            ; Restore the buffer index value
  1444.     xor    al,ah            ; Compute the next data byte value
  1445.     mov    es:[di+NIBBLE_BREAK],al ; Store the byte in the nibble buffer
  1446.     mov    ah,al            ; Move current byte to AH register
  1447.     dec    di            ; Decrement the index value
  1448.     jns    Loop_Break        ; Jump if more nibble break to process
  1449.     inc    di            ; Restore DI index to zero
  1450. Loop_Sector:
  1451.     lodsb                ; Get the next data byte to decode
  1452.     and    al,DECODE_MASK        ; Mask off all but the decode bits
  1453.     xchg    bx,dx            ; Get the decoding table into BX
  1454.     xlat    cs:[bx]         ; Decode the byte value through table
  1455.     xchg    bx,dx            ; Restore the buffer index value
  1456.     xor    al,ah            ; Compute the next data byte value
  1457.     mov    es:[di],al        ; Store the byte in the nibble buffer
  1458.     mov    ah,al            ; Move current byte to AH register
  1459.     inc    di            ; Increment the index value
  1460.     loop    Loop_Sector        ; Loop till all sector data processed
  1461.     Restore si,di,ds,es        ; Restore the buffer pointers
  1462.     call    Post_Nibble        ; Call routine to post-nibblize sector
  1463.     Restore ax,bx,cx,dx,di        ; Restore the required registers
  1464.     ret                ; Return to the caller
  1465. Decrypt_Sector    Endp            ; End of the Decrypt_Sector procedure
  1466.     Subttl    Read_Byte    Disk Controller Read Byte Routine
  1467.     Page    +
  1468. ;******************************************************************************
  1469. ;
  1470. ;    Read_Byte(Drive_Structure)
  1471. ;
  1472. ;        Save the required registers
  1473. ;        Get the track buffer pointer
  1474. ;        Get data byte from the buffer
  1475. ;        Increment the track buffer pointer
  1476. ;        If buffer pointer past limit value
  1477. ;            Zero the track buffer pointer
  1478. ;        Endif
  1479. ;        Restore the required registers
  1480. ;        Return to the caller
  1481. ;
  1482. ;    Registers on Entry:
  1483. ;
  1484. ;        ES:BX - Disk drive structure pointer
  1485. ;
  1486. ;    Registers on Exit:
  1487. ;
  1488. ;        AL    - Disk drive byte value
  1489. ;
  1490. ;******************************************************************************
  1491.         Even            ; Force procedure to even address
  1492. Read_Byte    Proc    Near        ; Disk read byte procedure
  1493.     Save    si            ; Save the required registers
  1494.     mov    si,es:[bx.Disk_Pointer] ; Get the current track buffer pointer
  1495.     mov    al,es:[bx.Disk_Buffer+si]
  1496.     inc    si            ; Increment track buffer pointer
  1497.     cmp    si,es:[bx.Disk_Limit]    ; Check against track buffer limit
  1498.     jb    Rd_Exit         ; Jump if track pointer valid
  1499.     xor    si,si            ; Zero the track pointer value
  1500. Rd_Exit:
  1501.     mov    es:[bx.Disk_Pointer],si ; Update current track buffer pointer
  1502.     Restore si            ; Restore the required registers
  1503.     ret                ; Return to the caller
  1504. Read_Byte    Endp            ; End of the Read_Byte procedure
  1505.     Subttl    Write_Byte    Disk Controller Write Byte Routine
  1506.     Page    +
  1507. ;******************************************************************************
  1508. ;
  1509. ;    Write_Byte(Drive_Structure)
  1510. ;
  1511. ;        Save the required registers
  1512. ;        Get the track buffer pointer
  1513. ;        Get the data byte to write (Write latch)
  1514. ;        If the data byte is valid (High order bit set)
  1515. ;            Write data byte to the buffer
  1516. ;        Endif
  1517. ;        Increment the track buffer pointer
  1518. ;        If buffer pointer past limit value
  1519. ;            Zero the track buffer pointer
  1520. ;        Endif
  1521. ;        Restore the required registers
  1522. ;        Return to the caller
  1523. ;
  1524. ;    Registers on Entry:
  1525. ;
  1526. ;        ES:BX - Disk drive structure pointer
  1527. ;
  1528. ;    Registers on Exit:
  1529. ;
  1530. ;        None
  1531. ;
  1532. ;******************************************************************************
  1533.         Even            ; Force procedure to even address
  1534. Write_Byte    Proc    Near        ; Disk write byte procedure
  1535.     Save    si            ; Save the required registers
  1536.     mov    si,es:[bx.Disk_Pointer] ; Get the current track buffer pointer
  1537.     mov    al,es:[bx.Disk_Latch]    ; Get the data byte to write
  1538.     or    al,al            ; Check for a valid data byte value
  1539.     jns    Skip_Write        ; Jump if illegal data byte value
  1540.     mov    es:[bx.Disk_Buffer+si],al
  1541. Skip_Write:
  1542.     inc    si            ; Increment track buffer pointer
  1543.     cmp    si,es:[bx.Disk_Limit]    ; Check against track buffer limit
  1544.     jb    Wr_Exit         ; Jump if track pointer valid
  1545.     xor    si,si            ; Zero the track pointer value
  1546. Wr_Exit:
  1547.     mov    es:[bx.Disk_Pointer],si ; Update current track buffer pointer
  1548.     Restore si            ; Restore the required registers
  1549.     ret                ; Return to the caller
  1550. Write_Byte    Endp            ; End of the Write_Byte procedure
  1551.     Subttl    Pre_Nibble    Disk Controller Pre-Nibblization Routine
  1552.     Page    +
  1553. ;******************************************************************************
  1554. ;
  1555. ;    Pre_Nibble(Sector_Area, Drive_Structure)
  1556. ;
  1557. ;        Save the required registers
  1558. ;        Get pointer to nibblization buffer
  1559. ;        Get nibble buffer sector break point (256 Bytes)
  1560. ;        Get desired type nibble break point (Counter value)
  1561. ;        Get starting buffer byte for nibblization
  1562. ;        While counter value > 0
  1563. ;            Get bytes from the sector buffer
  1564. ;            Rotate bits into position
  1565. ;            Update the nibblization buffer
  1566. ;            Update nibble buffer break area
  1567. ;            Update nibble and buffer pointers (Decrement counter)
  1568. ;        Endwhile
  1569. ;        Restore the required registers
  1570. ;        Return to the caller
  1571. ;
  1572. ;    Registers on Entry:
  1573. ;
  1574. ;        DS:SI - Pointer to sector area
  1575. ;        ES:BP - Disk drive structure pointer
  1576. ;
  1577. ;    Registers on Exit:
  1578. ;
  1579. ;        BX    - Destroyed
  1580. ;        SI    - Destroyed
  1581. ;
  1582. ;******************************************************************************
  1583.         Even            ; Force procedure to even address
  1584. Pre_Nibble    Proc    Near        ; Disk pre-nibblization procedure
  1585.     Save    cx,di,bp,es        ; Save the required registers
  1586.     test    es:[bp.Disk_Flag],OLD_STYLE
  1587.     jz    Nibble_New        ; Jump if a 16 sector type disk
  1588. Nibble_Old:
  1589.     mov    es,cs:[Nibble_Save]    ; Get the nibble buffer segment
  1590.     xor    di,di            ; Zero the nibble buffer offset
  1591.     mov    bp,NIBBLE_BREAK     ; Get nibble buffer sector break point
  1592.     mov    cx,BREAK_5_3        ; Get 5 to 3 nibble break point
  1593.     mov    bx,START_5_3        ; Get 5 to 3 starting byte
  1594. Loop_5_3:
  1595.     xor    ax,ax            ; Zero the AX register value
  1596.     mov    ah,ds:[si+bx]        ; Get a byte from the sector buffer
  1597.     shr    ah,1            ; Rotate
  1598.     rcl    al,1            ;     bits
  1599.     shr    ah,1            ;          into
  1600.     rcl    al,1            ;           the
  1601.     shr    ah,1            ;               correct
  1602.     rcl    al,1            ;                   position
  1603.     mov    es:[di+bx],ah        ; Update byte in the nibble buffer
  1604.     sub    bl,BREAK_5_3        ; Move to next byte in nibblization
  1605.     mov    ah,ds:[si+bx]        ; Get next byte from sector buffer
  1606.     shr    ah,1            ; Rotate
  1607.     rcl    al,1            ;     bits
  1608.     shr    ah,1            ;          into
  1609.     rcl    al,1            ;           the
  1610.     shr    ah,1            ;               correct
  1611.     rcl    al,1            ;                   position
  1612.     mov    es:[di+bx],ah        ; Update byte in the nibble buffer
  1613.     sub    bl,BREAK_5_3        ; Move to next byte in nibblization
  1614.     mov    es:[di+bp],al        ; Update nibble buffer break area
  1615.     add    bl,START_5_3        ; Correct the sector buffer pointer
  1616.     inc    bp            ; Correct nibble break pointer
  1617.     loop    Loop_5_3        ; Loop till all bytes processed
  1618.     jmp    Short Pre_Exit        ; Go return to the caller
  1619. Nibble_New:
  1620.     mov    es,cs:[Nibble_Save]    ; Get the nibble buffer segment
  1621.     xor    di,di            ; Zero the nibble buffer offset
  1622.     mov    bp,NIBBLE_BREAK     ; Get nibble buffer sector break point
  1623.     mov    cx,BREAK_6_2        ; Get 6 to 2 nibble break point
  1624.     mov    bx,START_6_2        ; Get 6 to 2 starting byte
  1625. Loop_6_2:
  1626.     xor    ax,ax            ; Zero the AX register value
  1627.     mov    ah,ds:[si+bx]        ; Get a byte from the sector buffer
  1628.     shr    ah,1            ; Rotate
  1629.     rcl    al,1            ;     bits into
  1630.     shr    ah,1            ;           correct
  1631.     rcl    al,1            ;               position
  1632.     mov    es:[di+bx],ah        ; Update byte in the nibble buffer
  1633.     sub    bl,BREAK_6_2        ; Move to next byte in nibblization
  1634.     mov    ah,ds:[si+bx]        ; Get next byte from sector buffer
  1635.     shr    ah,1            ; Rotate
  1636.     rcl    al,1            ;     bits into
  1637.     shr    ah,1            ;           correct
  1638.     rcl    al,1            ;               position
  1639.     mov    es:[di+bx],ah        ; Update byte in the nibble buffer
  1640.     sub    bl,BREAK_6_2        ; Move to next byte in nibblization
  1641.     mov    ah,ds:[si+bx]        ; Get next byte from sector buffer
  1642.     shr    ah,1            ; Rotate
  1643.     rcl    al,1            ;     bits into
  1644.     shr    ah,1            ;           correct
  1645.     rcl    al,1            ;               position
  1646.     mov    es:[di+bx],ah        ; Update byte in the nibble buffer
  1647.     sub    bl,BREAK_6_2        ; Move to next byte in nibblization
  1648.     mov    es:[di+bp],al        ; Update nibble buffer break area
  1649.     add    bl,START_6_2        ; Correct the sector buffer pointer
  1650.     inc    bp            ; Correct nibble break pointer
  1651.     loop    Loop_6_2        ; Loop till all bytes processed
  1652. Pre_Exit:
  1653.     Restore cx,di,bp,es        ; Restore the required registers
  1654.     ret                ; Return to the caller
  1655. Pre_Nibble    Endp            ; End of the Pre_Nibble procedure
  1656.     Subttl    Post_Nibble    Disk Controller Post-Nibblization Routine
  1657.     Page    +
  1658. ;******************************************************************************
  1659. ;
  1660. ;    Post_Nibble(Sector_Area, Drive_Structure)
  1661. ;
  1662. ;        Save the required registers
  1663. ;        Get pointer to nibblization buffer
  1664. ;        Get nibble buffer sector break point (256 Bytes)
  1665. ;        Get desired type nibble break point (Counter value)
  1666. ;        Get starting buffer byte for nibblization
  1667. ;        While counter value > 0
  1668. ;            Get bytes from the nibble buffer
  1669. ;            Rotate bits into position
  1670. ;            Update the sector buffer area
  1671. ;            Update nibble and buffer pointers (Decrement counter)
  1672. ;        Endwhile
  1673. ;        Restore the required registers
  1674. ;        Return to the caller
  1675. ;
  1676. ;    Registers on Entry:
  1677. ;
  1678. ;        DS:SI - Pointer to sector area
  1679. ;        ES:BP - Disk drive structure pointer
  1680. ;
  1681. ;    Registers on Exit:
  1682. ;
  1683. ;        BX    - Destroyed
  1684. ;        SI    - Destroyed
  1685. ;
  1686. ;******************************************************************************
  1687.         Even            ; Force procedure to even address
  1688. Post_Nibble    Proc    Near        ; Disk post-nibblization procedure
  1689.     Save    cx,di,bp,es        ; Save the required registers
  1690.     test    es:[bp.Disk_Flag],OLD_STYLE
  1691.     jz    New_Nibble        ; Jump if a 16 sector type disk
  1692. Old_Nibble:
  1693.     mov    es,cs:[Nibble_Save]    ; Get the nibble buffer segment
  1694.     xor    di,di            ; Zero the nibble buffer offset
  1695.     mov    bp,NIBBLE_BREAK     ; Get nibble buffer sector break point
  1696.     mov    cx,BREAK_5_3        ; Get 5 to 3 nibble break point
  1697.     mov    bx,BREAK_5_3 - 1    ; Get 5 to 3 starting byte
  1698. Next_5_3:
  1699.     mov    al,es:[di+bp]        ; Get break byte from nibble buffer
  1700.     mov    ah,es:[di+bx]        ; Get a byte from the nibble buffer
  1701.     shr    al,1            ; Rotate
  1702.     rcl    ah,1            ;     bits
  1703.     shr    al,1            ;          into
  1704.     rcl    ah,1            ;           the
  1705.     shr    al,1            ;               correct
  1706.     rcl    ah,1            ;                   position
  1707.     mov    ds:[si+bx],ah        ; Update byte in the sector buffer
  1708.     add    bl,BREAK_5_3        ; Move to next byte in nibblization
  1709.     mov    ah,es:[di+bx]        ; Get next byte from nibble buffer
  1710.     shr    al,1            ; Rotate
  1711.     rcl    ah,1            ;     bits
  1712.     shr    al,1            ;          into
  1713.     rcl    ah,1            ;           the
  1714.     shr    al,1            ;               correct
  1715.     rcl    ah,1            ;                   position
  1716.     mov    ds:[si+bx],ah        ; Update byte in the sector buffer
  1717.     add    bl,BREAK_5_3        ; Move to next byte in nibblization
  1718.     sub    bl,START_5_3 + 2    ; Correct the sector buffer pointer
  1719.     inc    bp            ; Correct nibble break pointer
  1720.     loop    Next_5_3        ; Loop till all bytes processed
  1721.     jmp    Short Post_Exit     ; Go return to the caller
  1722. New_Nibble:
  1723.     mov    es,cs:[Nibble_Save]    ; Get the nibble buffer segment
  1724.     xor    di,di            ; Zero the nibble buffer offset
  1725.     mov    bp,NIBBLE_BREAK     ; Get nibble buffer sector break point
  1726.     mov    cx,BREAK_6_2        ; Get 6 to 2 nibble break point
  1727.     mov    bx,BREAK_6_2 - 1    ; Get 6 to 2 starting byte
  1728. Next_6_2:
  1729.     mov    al,es:[di+bp]        ; Get break byte from nibble buffer
  1730.     mov    ah,es:[di+bx]        ; Get a byte from the nibble buffer
  1731.     shr    al,1            ; Rotate
  1732.     rcl    ah,1            ;     bits into
  1733.     shr    al,1            ;           correct
  1734.     rcl    ah,1            ;               position
  1735.     mov    ds:[si+bx],ah        ; Update byte in the sector buffer
  1736.     add    bl,BREAK_6_2        ; Move to next byte in nibblization
  1737.     mov    ah,es:[di+bx]        ; Get next byte from nibble buffer
  1738.     shr    al,1            ; Rotate
  1739.     rcl    ah,1            ;     bits into
  1740.     shr    al,1            ;           correct
  1741.     rcl    ah,1            ;               position
  1742.     mov    ds:[si+bx],ah        ; Update byte in the sector buffer
  1743.     add    bl,BREAK_6_2        ; Move to next byte in nibblization
  1744.     mov    ah,es:[di+bx]        ; Get next byte from nibble buffer
  1745.     shr    al,1            ; Rotate
  1746.     rcl    ah,1            ;     bits into
  1747.     shr    al,1            ;           correct
  1748.     rcl    ah,1            ;               position
  1749.     mov    ds:[si+bx],ah        ; Update byte in the sector buffer
  1750.     add    bl,BREAK_6_2        ; Move to next byte in nibblization
  1751.     sub    bl,START_6_2 + 2    ; Correct the sector buffer pointer
  1752.     inc    bp            ; Correct nibble break pointer
  1753.     loop    Next_6_2        ; Loop till all bytes processed
  1754. Post_Exit:
  1755.     Restore cx,di,bp,es        ; Restore the required registers
  1756.     ret                ; Return to the caller
  1757. Post_Nibble    Endp            ; End of the Post_Nibble procedure
  1758.     Page
  1759. ;******************************************************************************
  1760. ;
  1761. ;    Define the disk controller data structures
  1762. ;
  1763. ;******************************************************************************
  1764. Disk_Data    Equ    This Word    ; Define the disk data pointers
  1765.         Slot_Data    <>    ; Pointers to the disk data areas
  1766. Nibble_Save    Equ    This Word    ; Define nibblization save pointer
  1767.         Dw    0000h        ; Pointer to nibblization segment
  1768. Track_Save    Equ    This Word    ; Define track buffer save pointer
  1769.         Dw    0000h        ; Pointer to track buffer segment
  1770. Base_File    Disk_Name    <>    ; Define the base disk file name
  1771. Find_Data    Find_Match    <>    ; Define find match data area
  1772. Disk_Table    Equ    This Word    ; Define disk controller jump table
  1773.         Dw    No_Operation    ; Location C0x0h routine address
  1774.         Dw    Disk_Phase    ; Location C0x1h routine address
  1775.         Dw    No_Operation    ; Location C0x2h routine address
  1776.         Dw    Disk_Phase    ; Location C0x3h routine address
  1777.         Dw    No_Operation    ; Location C0x4h routine address
  1778.         Dw    Disk_Phase    ; Location C0x5h routine address
  1779.         Dw    No_Operation    ; Location C0x6h routine address
  1780.         Dw    Disk_Phase    ; Location C0x7h routine address
  1781.         Dw    Disk_Off    ; Location C0x8h routine address
  1782.         Dw    Disk_On     ; Location C0x9h routine address
  1783.         Dw    Select_A    ; Location C0xAh routine address
  1784.         Dw    Select_B    ; Location C0xBh routine address
  1785.         Dw    Data_Strobe    ; Location C0xCh routine address
  1786.         Dw    Load_Latch    ; Location C0xDh routine address
  1787.         Dw    Prepare_Input    ; Location C0xEh routine address
  1788.         Dw    Prepare_Output    ; Location C0xFh routine address
  1789. Nibble_5_3    Equ    This Byte    ; Define the 5 and 3 nibble table
  1790.         Db    0ABh, 0ADh, 0AEh, 0AFh, 0B5h, 0B6h, 0B7h, 0BAh
  1791.         Db    0BBh, 0BDh, 0BEh, 0BFh, 0D6h, 0D7h, 0DAh, 0DBh
  1792.         Db    0DDh, 0DEh, 0DFh, 0EAh, 0EBh, 0EDh, 0EEh, 0EFh
  1793.         Db    0F5h, 0F6h, 0F7h, 0FAh, 0FBh, 0FDh, 0FEh, 0FFh
  1794. Nibble_6_2    Equ    This Byte    ; Define the 6 and 2 nibble table
  1795.         Db    096h, 097h, 09Ah, 09Bh, 09Dh, 09Eh, 09Fh, 0A6h
  1796.         Db    0A7h, 0ABh, 0ACh, 0ADh, 0AEh, 0AFh, 0B2h, 0B3h
  1797.         Db    0B4h, 0B5h, 0B6h, 0B7h, 0B9h, 0BAh, 0BBh, 0BCh
  1798.         Db    0BDh, 0BEh, 0BFh, 0CBh, 0CDh, 0CEh, 0CFh, 0D3h
  1799.         Db    0D6h, 0D7h, 0D9h, 0DAh, 0DBh, 0DCh, 0DDh, 0DEh
  1800.         Db    0DFh, 0E5h, 0E6h, 0E7h, 0E9h, 0EAh, 0EBh, 0ECh
  1801.         Db    0EDh, 0EEh, 0EFh, 0F2h, 0F3h, 0F4h, 0F5h, 0F6h
  1802.         Db    0F7h, 0F9h, 0FAh, 0FBh, 0FCh, 0FDh, 0FEh, 0FFh
  1803. Decode_5_3    Equ    This Byte    ; Define the 5 and 3 decode table
  1804.         Db    000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
  1805.         Db    000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
  1806.         Db    000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
  1807.         Db    000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
  1808.         Db    000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
  1809.         Db    000h, 000h, 000h, 000h, 000h, 001h, 002h, 003h
  1810.         Db    003h, 003h, 003h, 003h, 003h, 004h, 005h, 006h
  1811.         Db    006h, 006h, 007h, 008h, 008h, 009h, 00Ah, 00Bh
  1812.         Db    00Bh, 00Bh, 00Bh, 00Bh, 00Bh, 00Bh, 00Bh, 00Bh
  1813.         Db    00Bh, 00Bh, 00Bh, 00Bh, 00Bh, 00Bh, 00Bh, 00Bh
  1814.         Db    00Bh, 00Bh, 00Bh, 00Bh, 00Bh, 00Bh, 00Ch, 00Dh
  1815.         Db    00Dh, 00Dh, 00Eh, 00Fh, 00Fh, 010h, 011h, 012h
  1816.         Db    012h, 012h, 012h, 012h, 012h, 012h, 012h, 012h
  1817.         Db    012h, 012h, 013h, 014h, 014h, 015h, 016h, 017h
  1818.         Db    017h, 017h, 017h, 017h, 017h, 018h, 019h, 01Ah
  1819.         Db    01Ah, 01Ah, 01Bh, 01Ch, 01Ch, 01Dh, 01Eh, 01Fh
  1820. Decode_6_2    Equ    This Byte    ; Define the 6 and 2 decode table
  1821.         Db    000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
  1822.         Db    000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
  1823.         Db    000h, 000h, 000h, 000h, 000h, 000h, 000h, 001h
  1824.         Db    001h, 001h, 002h, 003h, 003h, 004h, 005h, 006h
  1825.         Db    006h, 006h, 006h, 006h, 006h, 006h, 007h, 008h
  1826.         Db    008h, 008h, 008h, 009h, 00Ah, 00Bh, 00Ch, 00Dh
  1827.         Db    00Dh, 00Dh, 00Eh, 00Fh, 010h, 011h, 012h, 013h
  1828.         Db    013h, 014h, 015h, 016h, 017h, 018h, 019h, 01Ah
  1829.         Db    01Ah, 01Ah, 01Ah, 01Ah, 01Ah, 01Ah, 01Ah, 01Ah
  1830.         Db    01Ah, 01Ah, 01Ah, 01Bh, 01Bh, 01Ch, 01Dh, 01Eh
  1831.         Db    01Eh, 01Eh, 01Eh, 01Fh, 01Fh, 01Fh, 020h, 021h
  1832.         Db    021h, 022h, 023h, 024h, 025h, 026h, 027h, 028h
  1833.         Db    028h, 028h, 028h, 028h, 028h, 029h, 02Ah, 02Bh
  1834.         Db    02Bh, 02Ch, 02Dh, 02Eh, 02Fh, 030h, 031h, 032h
  1835.         Db    032h, 032h, 033h, 034h, 035h, 036h, 037h, 038h
  1836.         Db    038h, 039h, 03Ah, 03Bh, 03Ch, 03Dh, 03Eh, 03Fh
  1837. Skew_Table    Equ    This Byte    ; Sector skew table (Read skewing)
  1838.         Db    00h, 07h, 0Eh, 06h, 0Dh, 05h, 0Ch, 04h
  1839.         Db    0Bh, 03h, 0Ah, 02h, 09h, 01h, 08h, 0Fh
  1840. Disk_ID     Equ    This Byte    ; Disk controller ID string
  1841.         Db    "Disk Controller",0
  1842. ;******************************************************************************
  1843. ;
  1844. ;    Define the end of the Emulator Code Segment
  1845. ;
  1846. ;******************************************************************************
  1847. Emulate Ends
  1848.     End                ; End of the Disk module
  1849.