home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ddkx86v5.zip / DDKX86 / SRC / VDH / CGAREAD.ASM < prev    next >
Assembly Source File  |  1995-04-14  |  27KB  |  512 lines

  1. ;*DDK*************************************************************************/
  2. ;
  3. ; COPYRIGHT (C) Microsoft Corporation, 1989
  4. ; COPYRIGHT    Copyright (C) 1995 IBM Corporation
  5. ;
  6. ;    The following IBM OS/2 WARP source code is provided to you solely for
  7. ;    the purpose of assisting you in your development of OS/2 WARP device
  8. ;    drivers. You may use this code in accordance with the IBM License
  9. ;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
  10. ;    Copyright statement may not be removed.;
  11. ;*****************************************************************************/
  12.         PAGE    60,132
  13.         TITLE   CGAREAD.ASM -- CGA Buffer Read Routines
  14.  
  15. ;/*****************************************************************************
  16. ;*
  17. ;* SOURCE FILE NAME = CGAREAD.ASM
  18. ;*
  19. ;* DESCRIPTIVE NAME = CGA Buffer Read Routines 
  20. ;*
  21. ;*
  22. ;* VERSION      V2.0
  23. ;*
  24. ;* DATE         
  25. ;*
  26. ;* DESCRIPTION  BVS Device Handler for Windowable Sessions   
  27. ;*              This module contains the equivalent of the OS/2 1.1
  28. ;*              hooks for Windowable and Advanced VIO.
  29. ;*
  30. ;* FUNCTIONS    ReadCellTypes, ReadCharStr,
  31. ;*              ReadCellStr, LocateBuffAddr
  32. ;*
  33. ;* NOTES        NONE
  34. ;*             
  35. ;* STRUCTURES   NONE
  36. ;*
  37. ;* EXTERNAL REFERENCES  _MOVSW, MOVSB_SKIP_SI   
  38. ;*
  39. ;* EXTERNAL FUNCTIONS
  40. ;*
  41. ;*              NONE
  42. ;*
  43. ;* CHANGE ACTIVIY =
  44. ;*   DATE      FLAG       APAR    CHANGE DESCRIPTION
  45. ;*   --------  ---------- -----   --------------------------------------
  46. ;*   mm/dd/yy  @Vr.mpppxx xxxxx   xxxxxxx
  47. ;****************************************************************************/
  48.  
  49.         .286c                                     ; 286 protect mode instructions
  50.  
  51.         .xlist
  52.         INCLUDE struc.inc                         ; Structure macro
  53.         INCLUDE error2.inc                        ; Subsystem error equates
  54.         INCLUDE vdhstruc.inc                      ; Buffer update data structures
  55.         INCLUDE vdhequ.inc                        ; Buffer update equates
  56.         .list
  57.  
  58.         EXTRN   _MOVSW         : FAR              ; Move words from DS:SI to ES:DI
  59.         EXTRN   MOVSB_SKIP_SI  : FAR              ; Move bytes from DS:SI to ES:DI
  60.  
  61. R2CSEG  SEGMENT WORD PUBLIC 'CODE'
  62.         ASSUME  CS:R2CSEG,DS:NOTHING,ES:NOTHING
  63.  
  64. ;/****************************************************************************
  65. ;*                                                    
  66. ;* SUBROUTINE NAME:     ReadCellTypes                
  67. ;*                                                    
  68. ;* DESCRIPTIVE NAME:    Video device handler read cell types  
  69. ;*                                                    
  70. ;* FUNCTION:    Process read cell types sub-function.   
  71. ;*                                                    
  72. ;* ENTRY POINT: ReadCellTypes                         
  73. ;*   LINKAGE:   Near Call from BUFFERUPDATE rouinte   
  74. ;*                                                    
  75. ;* INPUT:                                             
  76. ;*                                                    
  77. ;* AX = 0                                             
  78. ;* SS:BP  --->  Stack frame                        (see VDHSTRUC.INC) 
  79. ;* DS:SI  --->  Parameter block buffer            (see CGABUFUP.ASM) 
  80. ;* ES:DI  --->  Mode data in environment buffer (see CGABUFUP.ASM) 
  81. ;*                                                    
  82. ;* PARAMETER BLOCK FORMAT:                            
  83. ;*                                                    
  84. ;*   SIZE   DESCRIPTION                               
  85. ;*   ----   -----------                               
  86. ;*                                                    
  87. ;*   WORD   Parameter length                          
  88. ;*   WORD   Flags                                      (source data buffer - LVB, PVB) 
  89. ;*   DWORD  Application data address  (target data buffer)  
  90. ;*   DWORD  Application data2 address (not used in this call)  
  91. ;*   WORD   Index (0)                                 
  92. ;*   WORD   Starting row                               (source row)   
  93. ;*   WORD   Starting column                            (source column)   
  94. ;*   WORD   Secondary row                              (not used in this call)  
  95. ;*   WORD   Secondary column                           (net used in this call)  
  96. ;*   WORD   RepeatFactor                               (input and output length)  
  97. ;*   WORD   LogicalBufSel                             
  98. ;*                                                    
  99. ;* OUTPUT:                                            
  100. ;*                                                    
  101. ;* EXIT-NORMAL: AX = 0                                
  102. ;*                                                    
  103. ;* EXIT-ERROR:  AX = Error from LocateBuffAddr      
  104. ;*                                                    
  105. ;* EFFECTS:     All                                   
  106. ;*                                                    
  107. ;* INTERNAL REFERENCES: LocateBuffAddr               
  108. ;*                                                    
  109. ;* EXTERNAL REFERENCES: _MOVSW                        
  110. ;*                                                    
  111. ;****************************************************************************/
  112.  
  113.         PUBLIC  ReadCellTypes
  114. ReadCellTypes   PROC    NEAR
  115.  
  116.         mov     bx, 1                              ; Set indicator for word move
  117.         call    LocateBuffAddr                     ; On exit: BX = sel, AX = off
  118.         .if     <nc>                               ; Continue?
  119.             shr     cx, 1                          ; Adjust for word move
  120.  
  121. ;/*
  122. ;**   On exit from LocateBuffAddr:                     
  123. ;**     If PVB & LVB flags are set then BX = LVB selector   
  124. ;**        [bp].PVB_Sel = PVB selector 
  125. ;**     else BX = LVB or PVB selector  
  126. ;**                                                     
  127. ;**   If both PVB and LVB are selected then the LVB must sync up with 
  128. ;**   PVB starting at the row, column until repeatfactor/2 is reached. 
  129. ;**   The valid cell type for this OS/2 release is a word of zero. 
  130. ;*/
  131.  
  132.             .if     <[bp].PVB_Sel a 0>             ; PVB & LVB flags set?
  133.                 push    ds                         ; Save parameter block addr
  134.                 push    si                         ; 
  135.                 push    cx                         ; Save repeat factor
  136.                 mov     ds, [bp].PVB_Sel           ; Use PVB as source
  137.                 mov     si, ax                     ; 
  138.                 mov     es, bx                     ; Use LVB as destination
  139.                 mov     di, ax                     ; 
  140.                 call    _MOVSW                     ; Refresh LVB from PVB
  141.                 pop     cx                         ; Restore repeat count
  142.                 pop     si                         ; Restore paramter block addr
  143.                 pop     ds                         ; 
  144.             .endif                                 ; 
  145.             les     di, [si].AppDataAddr           ; Setup destination address
  146.             sub     ax, ax                         ; Clear return code
  147.             rep     stosw                          ; Transfer zeros to user buffer
  148.         .endif                                     ; 
  149.         ret
  150.  
  151. ReadCellTypes   ENDP
  152.  
  153. ;/****************************************************************************
  154. ;*                                                    
  155. ;* SUBROUTINE NAME:     ReadCharStr                  
  156. ;*                                                    
  157. ;* DESCRIPTIVE NAME:    Video device handler read characters  
  158. ;*                                                    
  159. ;* FUNCTION:    Process read characters sub-function.   
  160. ;*              The characters are read from either PVB or LVB  
  161. ;*              starting at the specified row, column location.  
  162. ;*              Line wrap occurs if the end of a line is reached. 
  163. ;*              Read function is terminated if the end of PVB or 
  164. ;*              LVB is reached.  The characters read are placed  
  165. ;*              in the specified buffer and the number of chars  
  166. ;*              read is returned in the RepeatFactor field of  
  167. ;*              the parameter block.                 
  168. ;*                                                    
  169. ;* ENTRY POINT: ReadCharStr                           
  170. ;*   LINKAGE:   Near Call from BUFFERUPDATE routine   
  171. ;*                                                    
  172. ;* INPUT:                                             
  173. ;*                                                    
  174. ;* AX = 0                                             
  175. ;* SS:BP  --->  Stack frame                        (see VDHSTRUC.INC) 
  176. ;* DS:SI  --->  Parameter block buffer            (see CGABUFUP.ASM) 
  177. ;* ES:DI  --->  Mode data in environment buffer (see CGABUFUP.ASM) 
  178. ;*                                                    
  179. ;* PARAMETER BLOCK FORMAT:                            
  180. ;*                                                    
  181. ;*   SIZE   DESCRIPTION                               
  182. ;*   ----   -----------                               
  183. ;*                                                    
  184. ;*   WORD   Parameter length                          
  185. ;*   WORD   Flags                                      (source data buffer - LVB, PVB) 
  186. ;*   DWORD  Application data address  (target data buffer)  
  187. ;*   DWORD  Application data2 address (not used in this call)  
  188. ;*   WORD   Index (1)                                 
  189. ;*   WORD   Starting row                               (source row)   
  190. ;*   WORD   Starting column                            (source column)   
  191. ;*   WORD   Secondary row                              (not used in this call)  
  192. ;*   WORD   Secondary column                           (not used in this call)  
  193. ;*   WORD   RepeatFactor                               (input and output length)  
  194. ;*   WORD   LogicalBufSel                             
  195. ;*                                                    
  196. ;* OUTPUT:      Application data buffer = characters read  
  197. ;*              RepeatFactor = number of characters read  
  198. ;*                                                    
  199. ;* EXIT-NORMAL: AX = 0                                
  200. ;*                                                    
  201. ;* EXIT-ERROR:  AX = Error from LocateBuffAddr      
  202. ;*                                                    
  203. ;* EFFECTS:     All registers                         
  204. ;*                                                    
  205. ;* INTERNAL REFERENCES: LocateBuffAddr               
  206. ;*                                                    
  207. ;* EXTERNAL REFERENCES: _MOVSW, MOVSB_SKIP_SI       
  208. ;*                                                    
  209. ;****************************************************************************/
  210.  
  211.         PUBLIC  ReadCharStr
  212. ReadCharStr     PROC    NEAR
  213.  
  214.         sub     bx, bx                             ; Set indicator for byte move
  215.         call    LocateBuffAddr                     ; Setup LVB, PVB selectors
  216.         .if     <nc>                               ; Continue?
  217.  
  218. ;/*
  219. ;**   On exit from LocateBuffAddr:                     
  220. ;**     If PVB & LVB flags are set then BX = LVB selector   
  221. ;**        [bp].PVB_Sel = PVB selector 
  222. ;**     else BX = LVB or PVB selector  
  223. ;**                                                     
  224. ;**   If both PVB and LVB are selected then the information requested
  225. ;**   will be read into the LVB first before it is returned.
  226. ;*/
  227.  
  228.             .if     <[bp].PVB_Sel a 0>             ; PVB & LVB flags set?
  229.                 push    ds                         ; Save parameter block addr
  230.                 push    si                         ; 
  231.                 push    cx                         ; Save repeat factor
  232.                 push    ax                         ; 
  233.                 mov     ds, [bp].PVB_Sel           ; Use PVB as source
  234.                 mov     si, ax                     ; 
  235.                 mov     es, bx                     ; Use LVB as destination
  236.                 mov     di, ax                     ; 
  237.                 call    _MOVSW                     ; Refresh LVB from PVB
  238.                 pop     ax                         ; Restore LVB address
  239.                 pop     cx                         ; Restore repeat count
  240.                 pop     si                         ; Restore paramter block addr
  241.                 pop     ds                         ; 
  242.             .endif                                 ; 
  243.             les     di, [si].AppDataAddr           ; Setup destination address
  244.             mov     ds, bx                         ; Setup source selector
  245.             mov     si, ax                         ; Setup source offset
  246.             mov     bx, [bp].Retrace               ; Pass retrace information
  247.             call    MOVSB_SKIP_SI                  ; Read characters
  248.             sub     ax,ax                          ; Clear return code
  249.         .endif                                     ; 
  250.         ret
  251.  
  252. ReadCharStr     ENDP
  253.  
  254. ;/****************************************************************************
  255. ;*                                                    
  256. ;* SUBROUTINE NAME:     ReadCellStr                  
  257. ;*                                                    
  258. ;* DESCRIPTIVE NAME:    Video device handler read cells   
  259. ;*                                                    
  260. ;* FUNCTION:    Process read cells sub-function.   
  261. ;*              The cells are read from either PVB or LVB starting 
  262. ;*              at the specified row, column location. Line wrap 
  263. ;*              occurs if the end of a line is reached.  Read  
  264. ;*              function is terminated if the end of PVB or LVB  
  265. ;*              is reached.  The cells read are placed in the  
  266. ;*              specified buffer and the number of cells read  
  267. ;*              is returned in the RepeatFactor field of the  
  268. ;*              parameter block.                     
  269. ;*                                                    
  270. ;* ENTRY POINT: ReadCellStr                           
  271. ;*   LINKAGE:   Near Call from BUFFERUPDATE routine   
  272. ;*                                                    
  273. ;* INPUT:                                             
  274. ;*                                                    
  275. ;* AX =   0                                           
  276. ;* SS:BP  --->  Stack frame                        (see VDHSTRUC.INC) 
  277. ;* DS:SI  --->  Parameter block buffer            (see CGABUFUP.ASM) 
  278. ;* ES:DI  --->  Mode data in environment buffer (see CGABUFUP.ASM) 
  279. ;*                                                    
  280. ;* PARAMETER BLOCK FORMAT:                            
  281. ;*                                                    
  282. ;*   SIZE   DESCRIPTION                               
  283. ;*   ----   -----------                               
  284. ;*                                                    
  285. ;*   WORD   Parameter length                          
  286. ;*   WORD   Flags                                      (source data buffer - LVB, PVB) 
  287. ;*   DWORD  Application data address  (target data buffer)  
  288. ;*   DWORD  Application data2 address (not used in this call)  
  289. ;*   WORD   Index (2)                                 
  290. ;*   WORD   Starting row                               (source row)   
  291. ;*   WORD   Starting column                            (source column)   
  292. ;*   WORD   Secondary row                              (not used in this call)  
  293. ;*   WORD   Secondary column                           (not used in this call)  
  294. ;*   WORD   RepeatFactor                               (input and output length)  
  295. ;*   WORD   LogicalBufSel                             
  296. ;*                                                    
  297. ;* OUTPUT:      Application data buffer = character cells read  
  298. ;*              RepeatFactor = sum of char/attr pairs read  
  299. ;*                                                    
  300. ;* EXIT-NORMAL: AX = 0                                
  301. ;*                                                    
  302. ;* EXIT-ERROR:  AX = Error from LocateBuffAddr      
  303. ;*                                                    
  304. ;* EFFECTS:     All                                   
  305. ;*                                                    
  306. ;* INTERNAL REFERENCES: LocateBuffAddr               
  307. ;*                                                    
  308. ;* EXTERNAL REFERENCES: _MOVSW                        
  309. ;*                                                    
  310. ;****************************************************************************/
  311.  
  312.         PUBLIC  ReadCellStr
  313. ReadCellStr     PROC    NEAR
  314.  
  315.         mov     bx, 1                              ; Set indicator for word move
  316.         call    LocateBuffAddr                     ; On exit: BX = sel, AX = off
  317.         .if     <nc>                               ; Continue?
  318.             shr     cx, 1                          ; Adjust for word move
  319.  
  320. ;/*
  321. ;**   On exit from LocateBuffAddr:                     
  322. ;**     If PVB & LVB flags are set then BX = LVB selector   
  323. ;**        [bp].PVB_Sel = PVB selector 
  324. ;**     else BX = LVB or PVB selector  
  325. ;**                                                     
  326. ;**   If both PVB and LVB are selected then the information requested
  327. ;**   will be read into the LVB first before it is returned.
  328. ;*/
  329.  
  330.             .if     <[bp].PVB_Sel a 0>             ; PVB & LVB flags set?
  331.                 push    ds                         ; Save parameter block addr
  332.                 push    si                         ; 
  333.                 push    cx                         ; Save repeat factor
  334.                 push    bx                         ; Save LVB selecotr, offset
  335.                 push    ax                         ; 
  336.                 mov     ds, [bp].PVB_Sel           ; Use PVB as source
  337.                 mov     si, ax                     ; 
  338.                 mov     es, bx                     ; Use LVB as destination
  339.                 mov     di, ax                     ; 
  340.                 call    _MOVSW                     ; Refresh LVB from PVB
  341.                 pop     ax                         ; Restore LVB address
  342.                 pop     bx                         ; 
  343.                 pop     cx                         ; Restore repeat count
  344.                 pop     si                         ; Restore paramter block addr
  345.                 pop     ds                         ; 
  346.             .endif                                 ; 
  347.             les     di, [si].AppDataAddr           ; Setup destination address
  348.             mov     ds, bx                         ; Setup source selector
  349.             mov     si, ax                         ; Setup source offset
  350.             mov     bx, [bp].Retrace               ; Pass retrace information
  351.             call    _MOVSW                         ; Transfer cells to destination
  352.             sub     ax, ax                         ; Clear return code
  353.         .endif                                     ; 
  354.         ret                                        ; 
  355.  
  356. ReadCellStr     ENDP
  357.  
  358. ;/****************************************************************************
  359. ;*                                                    
  360. ;* SUBROUTINE NAME:     LocateBuffAddr               
  361. ;*                                                    
  362. ;* DESCRIPTIVE NAME:    Video device handler locate video buffer addr 
  363. ;*                                                    
  364. ;* FUNCTION:    Determine the source/target buffer address for the 
  365. ;*              read/write function based on the information in the 
  366. ;*              parameter buffer and the mode data buffer.  
  367. ;*                                                    
  368. ;* ENTRY POINT: LocateBuffAddr                        
  369. ;*   LINKAGE:   Near Call from ReadCharacters, ReadCells,  
  370. ;*                             RepeatAttribute,    
  371. ;*                                                    
  372. ;*                                                    
  373. ;* INPUT:                                             
  374. ;*                                                    
  375. ;* AX = 0                                             
  376. ;* BX = Type of transfer                              
  377. ;*      0 - byte transfer (character or attribute only)   
  378. ;*      1 - word transfer (character cell - char/attr pair)  
  379. ;* SS:BP  --->  Stack frame                        (see VDHSTRUC.INC) 
  380. ;* DS:SI  --->  Parameter block buffer            (see CGABUFUP.ASM) 
  381. ;* ES:DI  --->  Mode data in environment buffer (see CGABUFUP.ASM) 
  382. ;*                                                    
  383. ;* OUTPUT:      AX = source buffer offset           
  384. ;*              BX = source buffer selector         
  385. ;*              CX = adjusted repeat factor         
  386. ;*              DX = offset to the end of source buffer   
  387. ;*              DS:[SI].RepeatFactor = # of bytes to be transfered 
  388. ;*              CY = 1 Error encountered            
  389. ;*                                                    
  390. ;* EXIT-NORMAL: CY = clear                            
  391. ;*                                                    
  392. ;* EXIT-ERROR:  CY = set                              
  393. ;*              AX = 0  if RepeatFactor = 0 for char or attr move 
  394. ;*                                                = 0 or 1 for cell move  
  395. ;*              AX = ERROR_VIO_COL                   
  396. ;*              AX = ERROR_VIO_ROW                   
  397. ;*                                                    
  398. ;* EFFECTS:     AX, BX, CX, DX, CY                   
  399. ;*                                                    
  400. ;* INTERNAL REFERENCES: None                          
  401. ;*                                                    
  402. ;* EXTERNAL REFERENCES: None                          
  403. ;*
  404. ;****************************************************************************/
  405.  
  406.         PUBLIC  LocateBuffAddr
  407. LocateBuffAddr  PROC    NEAR
  408.  
  409.  
  410. ;/*
  411. ;**   Validate row, column value based on the current text mode setting.
  412. ;**   Make sure CY is set if validation fails.
  413. ;*/
  414.  
  415.         mov     cx, es:[di].TextCols              ; Get column value from EnvBuf
  416.         .if     <cx a [si].Col>                   ; Valid input column value?
  417.             mov     cx, es:[di].TextRows          ; Get row value from EnvBuf
  418.             .if     <cx a [si].Row>               ; Valid input row value?
  419.  
  420. ;/*
  421. ;**  Minimum transfer count for either character or attribute is 1 and
  422. ;**  the minimum transfer count for a cell is 2.
  423. ;**  Transfer will not take place if minimum transfer count is not met.
  424. ;**  This is determine by the request type indicated in BX on entry.
  425. ;*/
  426.  
  427.                 mov     cx, [si].RepeatFactor     ; Get repeat factor
  428.                 .if     <cx a bx>                 ; Pass minimum requirement?
  429.  
  430. ;/*
  431. ;**   Calculate the starting offset within the PVB or LVB based on the
  432. ;**   starting row, column value.
  433. ;*/
  434.  
  435.                     mov     ax, [si].Row          ; Buffer offset = (parm row
  436.                     mul     es:[di].TextCols      ;   * screen columns + parm
  437.                     add     ax, [si].Col          ;   column) * 2
  438.                     add     ax, ax                ; AX = buffer offset
  439.  
  440. ;/*
  441. ;**   Determine how many bytes left to the end of the video buffer.
  442. ;**   Length = size of PVB - video buffer offset
  443. ;*/
  444.  
  445.                     mov     dx, es:[di].BufferLenLo
  446.                     sub     dx, ax                ; Calculate eob length
  447.  
  448. ;/*
  449. ;**   For either character or attribute only transfer, cut the end of
  450. ;**   buffer length in half to allow for proper determination of buffer
  451. ;**   overflow condition.
  452. ;*/
  453.  
  454.                     .if     <zero bx>              ; Byte transfer request?
  455.                         shr                      dx, 1  ; Adjust end of buffer length
  456.                     .endif                         ; 
  457.  
  458. ;/*
  459. ;**   If overflow condition occurs, use the adjusted end-of-buffer
  460. ;**   length as the repeat factor count.
  461. ;*/
  462.  
  463.                     .if     <cx a dx>              ; Over flow buffer?
  464.                         mov    cx, dx              ; Repeat factor = eob length
  465.                     .endif                         ; 
  466.                     mov     [si].RepeatFactor, cx
  467.  
  468. ;/*
  469. ;**   Setup BX with either the PVB or LVB selector.  Selection of which 
  470. ;**   buffer to use is based on the Flags field in the parameter block. 
  471. ;**                                                     
  472. ;**   If both PVB and LVB flag bits are ON            
  473. ;**   then                                              
  474. ;**       BX = LVB selector                             
  475. ;**       [bp].PVB_Sel = PVB selector                  
  476. ;**   else                                              
  477. ;**       BX = LVB or PVB as indicated by either of the two flag bits 
  478. ;*/
  479.  
  480.                     mov     bx, [bp].PVB_Sel        ; Assume PVB update
  481.                     test    [si].Flags, LVB_SEL_BIT ; 
  482.                     .if     <nz>                    ; LVB requested?
  483.                         test                     [si].Flags, PVB_SEL_BIT ; 
  484.                         .if                      <z>  ; LVB update only?
  485.                             mov     [bp].PVB_Sel, 0 ; Indicate as such
  486.                         .endif                      ; 
  487.                         mov        bx, [si].LogicalBufSel ; Use LVB instead
  488.                     .else                           ; PVB only!
  489.                         mov        [bp].PVB_Sel, 0  ; Indicate BX has PVB
  490.                         inc        [bp].Retrace     ; Retrace wait required
  491.                     .endif                          ; 
  492.                     clc                             ; Normal completion
  493.                 .else                               ; 
  494.                     sub     ax, ax                  ; Clear return code
  495.                     mov     [si].RepeatFactor, ax   ; Indicate no-op
  496.                     stc                             ; Force exit condition
  497.                 .endif                              ; 
  498.             .else                                   ; 
  499.                 mov     ax, ERROR_VIO_ROW           ; 
  500.                 stc                                 ; 
  501.             .endif                                  ; 
  502.         .else                                       ; 
  503.             mov     ax, ERROR_VIO_COL               ; 
  504.             stc                                     ; 
  505.         .endif                                      ; 
  506.         ret                                         ; 
  507.  
  508. LocateBuffAddr  ENDP
  509.  
  510. R2CSEG  ENDS
  511.         END
  512.