home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / C / TGE129D / 1024X768.ASM next >
Assembly Source File  |  1993-09-02  |  42KB  |  2,028 lines

  1. ; 1024x768x256 (requires register-compatible VGA+)
  2. ; Loadable driver for The Graphics Engine
  3. ; Copyright (c) 1993 by Matthew Hildebrand
  4. ; Turbo Assembler syntax
  5. ; Portions by John Bridges
  6.  
  7. IDEAL
  8. MODEL LARGE TGE1024X768_TEXT
  9. P386N
  10.  
  11.  
  12. SCREEN_WIDE    =    1024
  13. SCREEN_DEEP    =    768
  14. NUM_COLOURS    =    256
  15.  
  16.  
  17.         CODESEG TGE1024X768_TEXT
  18.         ORG    0
  19.  
  20. ;*** Signature
  21.             db    'TGE3'
  22. ;*** Non-I/O functions
  23. _initGraphics        dw    initGraphics        ; initGraphics
  24.             dw    ?
  25. _deInitGraphics        dw    0            ; deInitGraphics
  26.             dw    ?
  27. _setPaletteReg        dw    setPaletteReg        ; setPaletteReg
  28.             dw    ?
  29. _getPaletteReg        dw    getPaletteReg        ; getPaletteReg
  30.             dw    ?
  31. _setBlockPalette    dw    setBlockPalette        ; setBlockPalette
  32.             dw    ?
  33. _getBlockPalette    dw    getBlockPalette        ; getBlockPalette
  34.             dw    ?
  35. _colourCloseTo        dw    0            ; colourCloseTo
  36.             dw    ?
  37. _colourCloseToX        dw    0            ; colourCloseToX
  38.             dw    ?
  39. _imageSize        dw    0            ; imageSize
  40.             dw    ?
  41. _imageSizeDim        dw    0            ; imageSizeDim
  42.             dw    ?
  43. _setPage        dw    0            ; setPage (not implemented yet)
  44.             dw    ?
  45.  
  46. ;*** Currently active I/O functions (filled in by loadGraphDriver())
  47.             dd    20    DUP(?)
  48.  
  49. ;*** Input functions
  50. _getImage_scr        dw    0            ; getImage
  51.             dw    ?
  52. _getImage_mem        dw    0
  53.             dw    ?
  54. _getLine_scr        dw      getLine_scr              ; getLine
  55.             dw    ?
  56. _getLine_mem        dw    getLine_mem
  57.             dw    ?
  58. _getPixel_scr        dw    getPixel_scr        ; getPixel
  59.             dw    ?
  60. _getPixel_mem        dw    getPixel_mem
  61.             dw    ?
  62.  
  63. ;*** Output functions
  64. _putImage_scr_copy    dw    0            ; putImage
  65.             dw    ?
  66. _putImage_scr_and    dw    0
  67.             dw    ?
  68. _putImage_scr_not    dw    0
  69.             dw    ?
  70. _putImage_scr_or    dw    0
  71.             dw    ?
  72. _putImage_scr_xor    dw    0
  73.             dw    ?
  74. _putImage_mem_copy    dw    0
  75.             dw    ?
  76. _putImage_mem_and    dw    0
  77.             dw    ?
  78. _putImage_mem_not    dw    0
  79.             dw    ?
  80. _putImage_mem_or    dw    0
  81.             dw    ?
  82. _putImage_mem_xor    dw    0
  83.             dw    ?
  84. _putImageInv_scr_copy    dw    0            ; putImageInv
  85.             dw    ?
  86. _putImageInv_scr_and    dw    0
  87.             dw    ?
  88. _putImageInv_scr_not    dw      0
  89.             dw    ?
  90. _putImageInv_scr_or    dw      0
  91.             dw    ?
  92. _putImageInv_scr_xor    dw    0
  93.             dw    ?
  94. _putImageInv_mem_copy    dw    0
  95.             dw    ?
  96. _putImageInv_mem_and    dw    0
  97.             dw    ?
  98. _putImageInv_mem_not    dw    0
  99.             dw    ?
  100. _putImageInv_mem_or    dw    0
  101.             dw    ?
  102. _putImageInv_mem_xor    dw    0
  103.             dw    ?
  104. _putLine_scr_copy          dw    putLine_scr_copy    ; putLine
  105.             dw    ?
  106. _putLine_scr_and          dw      0
  107.             dw    ?
  108. _putLine_scr_not          dw      0
  109.             dw    ?
  110. _putLine_scr_or          dw      0
  111.             dw    ?
  112. _putLine_scr_xor          dw    0
  113.             dw    ?
  114. _putLine_mem_copy    dw      putLine_mem_copy
  115.             dw    ?
  116. _putLine_mem_and    dw      0
  117.             dw    ?
  118. _putLine_mem_not    dw      0
  119.             dw    ?
  120. _putLine_mem_or        dw      0
  121.             dw    ?
  122. _putLine_mem_xor    dw    0
  123.             dw    ?
  124. _putLineInv_scr_copy       dw    0            ; putLineInv
  125.             dw    ?
  126. _putLineInv_scr_and       dw    0
  127.             dw    ?
  128. _putLineInv_scr_not       dw    0
  129.             dw    ?
  130. _putLineInv_scr_or       dw    0
  131.             dw    ?
  132. _putLineInv_scr_xor       dw    0
  133.             dw    ?
  134. _putLineInv_mem_copy    dw    putLineInv_mem_copy
  135.             dw    ?
  136. _putLineInv_mem_and    dw    0
  137.             dw    ?
  138. _putLineInv_mem_not    dw    0
  139.             dw    ?
  140. _putLineInv_mem_or    dw    0
  141.             dw    ?
  142. _putLineInv_mem_xor    dw    0
  143.             dw    ?
  144. _putPixel_scr_copy    dw    putPixel_scr_copy    ; putPixel
  145.             dw    ?
  146. _putPixel_scr_and    dw      0
  147.             dw    ?
  148. _putPixel_scr_not    dw      0
  149.             dw    ?
  150. _putPixel_scr_or    dw      0
  151.             dw    ?
  152. _putPixel_scr_xor    dw    0
  153.             dw    ?
  154. _putPixel_mem_copy    dw    putPixel_mem_copy
  155.             dw    ?
  156. _putPixel_mem_and    dw      putPixel_mem_and
  157.             dw    ?
  158. _putPixel_mem_not    dw      putPixel_mem_not
  159.             dw    ?
  160. _putPixel_mem_or    dw      putPixel_mem_or
  161.             dw    ?
  162. _putPixel_mem_xor    dw    putPixel_mem_xor
  163.             dw    ?
  164. _line_scr_copy        dw    0            ; line
  165.             dw    ?
  166. _line_scr_and        dw      0
  167.             dw    ?
  168. _line_scr_not        dw      0
  169.             dw    ?
  170. _line_scr_or        dw      0
  171.             dw    ?
  172. _line_scr_xor        dw    0
  173.             dw    ?
  174. _line_mem_copy        dw    0
  175.             dw    ?
  176. _line_mem_and        dw    0
  177.             dw    ?
  178. _line_mem_not        dw    0
  179.             dw    ?
  180. _line_mem_or        dw    0
  181.             dw    ?
  182. _line_mem_xor        dw    0
  183.             dw    ?
  184. _horizLine_scr_copy    dw    horizLine_scr_copy      ; horizLine
  185.             dw    ?
  186. _horizLine_scr_and    dw      0
  187.             dw    ?
  188. _horizLine_scr_not    dw      0
  189.             dw    ?
  190. _horizLine_scr_or    dw      0
  191.             dw    ?
  192. _horizLine_scr_xor    dw    0
  193.             dw    ?
  194. _horizLine_mem_copy    dw    horizLine_mem_copy
  195.             dw    ?
  196. _horizLine_mem_and    dw      0
  197.             dw    ?
  198. _horizLine_mem_not    dw      0
  199.             dw    ?
  200. _horizLine_mem_or    dw      0
  201.             dw    ?
  202. _horizLine_mem_xor    dw    0
  203.             dw    ?
  204. _vertLine_scr_copy    dw    0             ; vertLine
  205.             dw    ?
  206. _vertLine_scr_and    dw    0
  207.             dw    ?
  208. _vertLine_scr_not    dw    0
  209.             dw    ?
  210. _vertLine_scr_or    dw    0
  211.             dw    ?
  212. _vertLine_scr_xor    dw    0
  213.             dw    ?
  214. _vertLine_mem_copy    dw    0
  215.             dw    ?
  216. _vertLine_mem_and    dw    0
  217.             dw    ?
  218. _vertLine_mem_not    dw    0
  219.             dw    ?
  220. _vertLine_mem_or    dw    0
  221.             dw    ?
  222. _vertLine_mem_xor    dw    0
  223.             dw    ?
  224. _drawRect_scr_copy    dw    0            ; drawRect
  225.             dw    ?
  226. _drawRect_scr_and    dw    0
  227.             dw    ?
  228. _drawRect_scr_not    dw    0
  229.             dw    ?
  230. _drawRect_scr_or    dw    0
  231.             dw    ?
  232. _drawRect_scr_xor    dw    0
  233.             dw    ?
  234. _drawRect_mem_copy    dw    0
  235.             dw    ?
  236. _drawRect_mem_and    dw    0
  237.             dw    ?
  238. _drawRect_mem_not    dw    0
  239.             dw    ?
  240. _drawRect_mem_or    dw    0
  241.             dw    ?
  242. _drawRect_mem_xor    dw    0
  243.             dw    ?
  244. _filledRect_scr_copy    dw    0            ; filledRect
  245.             dw    ?
  246. _filledRect_scr_and    dw      0
  247.             dw    ?
  248. _filledRect_scr_not    dw      0
  249.             dw    ?
  250. _filledRect_scr_or    dw      0
  251.             dw    ?
  252. _filledRect_scr_xor    dw    0
  253.             dw    ?
  254. _filledRect_mem_copy    dw    0
  255.             dw    ?
  256. _filledRect_mem_and    dw    0
  257.             dw    ?
  258. _filledRect_mem_not    dw    0
  259.             dw    ?
  260. _filledRect_mem_or    dw    0
  261.             dw    ?
  262. _filledRect_mem_xor    dw    0
  263.             dw    ?
  264. _clearGraphics_scr_copy    dw    0            ; clearGraphics
  265.             dw    ?
  266. _clearGraphics_scr_and    dw      0
  267.             dw    ?
  268. _clearGraphics_scr_not    dw      0
  269.             dw    ?
  270. _clearGraphics_scr_or    dw      0
  271.             dw    ?
  272. _clearGraphics_scr_xor    dw    0
  273.             dw    ?
  274. _clearGraphics_mem_copy    dw    0
  275.             dw    ?
  276. _clearGraphics_mem_and    dw    0
  277.             dw    ?
  278. _clearGraphics_mem_not    dw    0
  279.             dw    ?
  280. _clearGraphics_mem_or    dw    0
  281.             dw    ?
  282. _clearGraphics_mem_xor    dw    0
  283.             dw    ?
  284. _ellipse_scr_copy    dw    0            ; ellipse
  285.             dw    ?
  286. _ellipse_scr_and    dw    0
  287.             dw    ?
  288. _ellipse_scr_not    dw    0
  289.             dw    ?
  290. _ellipse_scr_or        dw    0
  291.             dw    ?
  292. _ellipse_scr_xor    dw    0
  293.             dw    ?
  294. _ellipse_mem_copy    dw    0
  295.             dw    ?
  296. _ellipse_mem_and    dw    0
  297.             dw    ?
  298. _ellipse_mem_not    dw    0
  299.             dw    ?
  300. _ellipse_mem_or        dw    0
  301.             dw    ?
  302. _ellipse_mem_xor    dw    0
  303.             dw    ?
  304. _filledEllipse_scr_copy    dw    0            ; filledEllipse
  305.             dw    ?
  306. _filledEllipse_scr_and    dw    0
  307.             dw    ?
  308. _filledEllipse_scr_not    dw    0
  309.             dw    ?
  310. _filledEllipse_scr_or    dw    0
  311.             dw    ?
  312. _filledEllipse_scr_xor    dw    0
  313.             dw    ?
  314. _filledEllipse_mem_copy    dw    0
  315.             dw    ?
  316. _filledEllipse_mem_and    dw    0
  317.             dw    ?
  318. _filledEllipse_mem_not    dw    0
  319.             dw    ?
  320. _filledEllipse_mem_or    dw    0
  321.             dw    ?
  322. _filledEllipse_mem_xor    dw    0
  323.             dw    ?
  324. _circle_scr_copy    dw    0            ; circle
  325.             dw    ?
  326. _circle_scr_and        dw    0
  327.             dw    ?
  328. _circle_scr_not        dw    0
  329.             dw    ?
  330. _circle_scr_or        dw    0
  331.             dw    ?
  332. _circle_scr_xor        dw    0
  333.             dw    ?
  334. _circle_mem_copy    dw    0
  335.             dw    ?
  336. _circle_mem_and        dw    0
  337.             dw    ?
  338. _circle_mem_not        dw    0
  339.             dw    ?
  340. _circle_mem_or        dw    0
  341.             dw    ?
  342. _circle_mem_xor        dw    0
  343.             dw    ?
  344. _filledCircle_scr_copy    dw    0            ; filledCircle
  345.             dw    ?
  346. _filledCircle_scr_and    dw    0
  347.             dw    ?
  348. _filledCircle_scr_not    dw    0
  349.             dw    ?
  350. _filledCircle_scr_or    dw    0
  351.             dw    ?
  352. _filledCircle_scr_xor    dw    0
  353.             dw    ?
  354. _filledCircle_mem_copy    dw    0
  355.             dw    ?
  356. _filledCircle_mem_and    dw    0
  357.             dw    ?
  358. _filledCircle_mem_not    dw    0
  359.             dw    ?
  360. _filledCircle_mem_or    dw    0
  361.             dw    ?
  362. _filledCircle_mem_xor    dw    0
  363.             dw    ?
  364. _fillRegion_scr_copy    dw    0            ; fillRegion
  365.             dw    ?
  366. _fillRegion_scr_and    dw    0
  367.             dw    ?
  368. _fillRegion_scr_not    dw    0
  369.             dw    ?
  370. _fillRegion_scr_or    dw    0
  371.             dw    ?
  372. _fillRegion_scr_xor    dw    0
  373.             dw    ?
  374. _fillRegion_mem_copy    dw    0
  375.             dw    ?
  376. _fillRegion_mem_and    dw    0
  377.             dw    ?
  378. _fillRegion_mem_not    dw    0
  379.             dw    ?
  380. _fillRegion_mem_or    dw    0
  381.             dw    ?
  382. _fillRegion_mem_xor    dw    0
  383.             dw    ?
  384. _fillLine_scr_copy    dw    horizLine_scr_copy    ; fillLine
  385.             dw    ?
  386. _fillLine_scr_and    dw      0
  387.             dw    ?
  388. _fillLine_scr_not    dw      0
  389.             dw    ?
  390. _fillLine_scr_or    dw      0
  391.             dw    ?
  392. _fillLine_scr_xor    dw    0
  393.             dw    ?
  394. _fillLine_mem_copy    dw    horizLine_mem_copy
  395.             dw    ?
  396. _fillLine_mem_and    dw      0
  397.             dw    ?
  398. _fillLine_mem_not    dw      0
  399.             dw    ?
  400. _fillLine_mem_or    dw      0
  401.             dw    ?
  402. _fillLine_mem_xor    dw    0
  403.             dw    ?
  404. ;*** Mode information
  405. scrnMaxX        dw    1023    ; physical dimensions
  406. scrnMaxY        dw    767
  407. maxColour        dw    255    ; maximum colour number
  408. xRatio                   dw    4    ; aspect ratio 4:3 (1024:768 in
  409. yRatio            dw    3    ;   lowest terms)
  410. bitsPerPixel        dw    8    ; 8 bits per pixel
  411. inMaxX            dw    1023    ; current input screen dimensions
  412. inMaxY            dw    767
  413. outMaxX            dw    1023    ; current output screen dimensions
  414. outMaxY            dw    767
  415. inScreenWide        dw    ?    ; needed only for virtual screens
  416. outScreenWide        dw    ?
  417. ;*** Viewport information
  418. inViewportULX        dw    0
  419. inViewportULY        dw    0
  420. inViewportLRX        dw    1023
  421. inViewportLRY        dw    767
  422. outViewportULX        dw    0
  423. outViewportULY        dw    0
  424. outViewportLRX        dw    1023
  425. outViewportLRY        dw    767
  426. ;*** Paging information
  427. pagingSupported        dw    ?    ; not implemented yet
  428. curPage            dw    ?    ; not implemented yet
  429. maxPage            dw    ?    ; not implemented yet
  430. ;*** Force (image width MOD imageWideAdjust) = 0.
  431. imageWideAdjust        dw    ?    ; not implemented yet
  432. ;*** Current and screen addresses
  433.     LABEL    inAddr    DWORD        ; current input address
  434. inOff    dw    0
  435. inSeg    dw    0A000h
  436.     LABEL    outAddr    DWORD        ; current output address
  437. outOff    dw    0
  438. outSeg    dw    0A000h
  439.     LABEL    scrAddr    DWORD        ; screen address
  440. scrOff    dw    0
  441. scrSeg    dw    0A000h
  442. ;*** Copyright string
  443.     db    'The Graphics Engine -- Copyright (c) 1993 by Matthew Hildebrand'
  444.  
  445.  
  446. inited        db    0
  447. colourPalette    db    768    DUP(?)
  448. lineOffs    dw    SCREEN_DEEP    DUP(?)
  449. bankNum        dw    SCREEN_DEEP    DUP(?)
  450. bankChanges    dw    SCREEN_DEEP    DUP(?)
  451. curBank        dw    ?
  452. screenWide    dw    ?
  453.  
  454. bankadr        dw    OFFSET _nobank
  455. vgamem        dw    ?
  456. bksize        dw    ?
  457. bksizeShl10Dec    dw    ?
  458. retval        dw    ?        ; first return value from whichVGA()
  459. scanline    dw    ?
  460.  
  461. aheadb        dw    ?
  462. ativga        dw    ?
  463. chipstech    dw    ?
  464. everex        dw    ?
  465. oak067        dw    ?
  466. t8900        dw    ?
  467. tseng4        dw    ?
  468. vesa        dw    ?
  469.  
  470.  
  471. ; VESA information
  472.     STRUC    vgainfo
  473. VESASignature    db    4 dup (?)    ; 4 signature bytes
  474. VESAVersion    dw    ?        ; VESA version number
  475. OEMStringPtr    dd    ?        ; Pointer to OEM string
  476. Capabilities    db    4 dup (?)    ; Capabilities of the video environment
  477. VideoModePtr    dd    ?        ; Pointer to supported Super VGA modes
  478.     ENDS
  479.     STRUC    vesamode
  480. ModeAttributes    dw    ?    ; mode attributes
  481. WinAAttributes    db    ?    ; window A attributes
  482. WinBAttributes    db    ?    ; window B attributes
  483. WinGranularity    dw    ?    ; window granularity
  484. WinSize        dw    ?    ; window size
  485. WinASegment    dw    ?    ; window A start segment
  486. WinBSegment    dw    ?    ; window B start segment
  487. WinFuncPtr    dd    ?    ; pointer to window function
  488. BytesPerLine    dw    ?    ; bytes per scan line
  489. ;
  490. ; optional information (provided if bit D1 of ModeAttributes is set)
  491. ;
  492. XResolution    dw    ?    ; horizontal resolution
  493. YResolution    dw    ?    ; vertical resolution
  494. XCharSize    db    ?    ; character cell width
  495. YCharSize    db    ?    ; character cell height
  496. NumberOfPlanes    db    ?    ; number of memory planes
  497. BitsPerPixel    db    ?    ; bits per pixel
  498. NumberOfBanks    db    ?    ; number of banks
  499. MemoryModel    db    ?    ; memory model type
  500. BankSize    db    ?    ; bank size in kb
  501.     db    227    DUP(?)    ; pad to 256 bytes
  502.     ENDS
  503.  
  504. vesabuf        db    256    DUP(?)
  505. modebuf        vesamode    ?
  506.  
  507.  
  508. MACRO    NEWBANK
  509.   call    [bankadr]
  510. ENDM
  511.  
  512.  
  513. ;*****
  514. ;***** initGraphics
  515. ;*****
  516.  
  517. PROC    C    initGraphics
  518.   cmp    [inited],0
  519.   je    @@NotInited
  520.   call    setMode
  521.   mov    ax,1
  522.   retf
  523.  
  524.     @@NotInited:
  525.   call    whichVGA
  526.   or    ax,ax                ; was function successful?
  527.   jz    @@Error                ; no, quit
  528.   call    setMode
  529.   or    ax,ax                ; was function successful?
  530.   jz    @@Error                     ; no, quit
  531.   call    makeAddrTable
  532.  
  533.   cmp    [vgamem],1024            ; ensure enough memory
  534.   jb    @@Error                ; abort if <1024 K of video RAM
  535.  
  536.   mov    ax,[bksize]            ; initialize bksizeShl10Dec
  537.   shl    ax,10                ; shift it
  538.   dec    ax                ; decrement it
  539.   mov    [bksizeShl10Dec],ax        ; store it
  540.  
  541.   mov    ax,1
  542.   mov    [inited],al
  543.   retf
  544.  
  545.     @@Error:
  546.   xor    ax,ax
  547.   retf
  548. ENDP
  549.  
  550.  
  551. ;*****
  552. ;***** putLine
  553. ;*****
  554.  
  555. PROC    C    putLine_scr_copy
  556.     ARG    y:WORD, xOff:WORD, lineLen:WORD, buf:DWORD
  557.   push    ds si di
  558.  
  559.   cld
  560.   mov    bx,[y]                ; Decide if bank changes mid-line
  561.   shl    bx,1
  562.   cmp    [cs:bankChanges+bx],0
  563.   jne    @@BankChanged
  564.  
  565.   mov    ax,[cs:bankNum+bx]
  566.   cmp    ax,[curBank]            ; set bank only if necessary
  567.   je    @@NoNewBank
  568.   NEWBANK
  569.  
  570.     @@NoNewBank:
  571.   mov    cx,[lineLen]            ; blast the line into video memory
  572.   mov    ax,0A000h
  573.   mov    es,ax
  574.   mov    di,[cs:lineOffs+bx]
  575.   add    di,[xOff]
  576.   lds    si,[buf]
  577.   mov    dx,cx                ; DX = CX
  578.   shr    cx,2                ; CX = line length in dwords
  579.   rep    movsd                ; copy the dwords
  580.   mov    cx,dx                ; CX = line length in bytes
  581.   and    cx,0000000000000011b        ; CX = number of residual bytes
  582.   rep    movsb                ; copy the residual bytes, if any
  583.   pop    di si ds            ; restore registers
  584.   leave                        ; clean up call stack
  585.   retf                    ; return
  586.  
  587.     @@BankChanged:                  ; slow pixel-by-pixel
  588.   mov    cx,[lineLen]
  589.   mov    dx,[y]
  590.   mov    bx,[xOff]
  591.   lds    si,[buf]
  592.     @@Loop:
  593.   lodsb
  594.   push    bx cx dx si
  595.   call    far putPixel_scr_copy C,bx,dx,ax
  596.   pop    si dx cx bx
  597.   inc    bx
  598.   loop    @@Loop
  599.  
  600.   pop    di si ds
  601.   leave
  602.   retf
  603. ENDP
  604.  
  605. PROC    C    putLine_mem_copy
  606.     ARG    y:WORD, xOff:WORD, lineLen:WORD, buf:DWORD
  607.   push    ds si di            ; save these registers
  608.  
  609.   xor    eax,eax                ; clear EAX
  610.   xor    edx,edx                ; clear EDX
  611.   xor    edi,edi                ; clear EDI
  612.  
  613.   les    di,[outAddr]            ; load output address
  614.   mov    ax,[y]
  615.   mov    dx,[outScreenWide]
  616.   mul    edx                    ; EDX:EAX = offset - EDI - x
  617.   add    edi,eax                ; EDI = offset - x
  618.   mov    dx,[xOff]
  619.   add    edi,edx                ; EDI = offset
  620.   mov    edx,edi                ; EDX = offset
  621.   shr    edx,4                ; EDX = # of paragraphs (segments)
  622.   add    dx,[outSeg]            ; DX = new segment
  623.   mov    es,dx                ; ES = new segment
  624.   and    di,0000000000001111b             ; DI = offset within new segment
  625.  
  626.   lds    si,[buf]            ; load input address
  627.   mov    dx,si                ; DX = offset
  628.   shr    dx,4                ; DX = # of paragraphs (segments)
  629.   mov    ax,ds                ; AX = DS
  630.   add    ax,dx                ; AX = new DS
  631.   mov    ds,ax                ; DS = new DS
  632.   and    si,0000000000001111b        ; SI = offset within new segment
  633.  
  634.   cld
  635.   mov    cx,[lineLen]            ; CX = line length
  636.   mov    dx,cx                ; DX = line length
  637.   shr    cx,2                ; CX = line length in dwords
  638.   rep    movsd                     ; move the dwords if necessary
  639.   mov    cx,dx                ; CX = line length in bytes
  640.   and    cx,0000000000000011b        ; CX = any residual bytes
  641.   rep    movsb                ; move the bytes if necessary
  642.  
  643.   pop    di si ds            ; restore registers
  644.   leave                    ; clean up
  645.   retf                    ; return
  646. ENDP
  647.  
  648.  
  649. ;*****
  650. ;***** putLineInv
  651. ;*****
  652.  
  653. PROC    C    putLineInv_mem_copy
  654.     ARG    y:WORD, xOff:WORD, lineLen:WORD, buf:DWORD
  655.   push    ds si di            ; save these registers
  656.  
  657.   xor    eax,eax                ; clear EAX
  658.   xor    edx,edx                ; clear EDX
  659.   xor    edi,edi                ; clear EDI
  660.  
  661.   les    di,[outAddr]            ; load output address
  662.   mov    ax,[y]
  663.   mov    dx,[outScreenWide]
  664.   mul    edx                    ; EDX:EAX = offset - EDI - x
  665.   add    edi,eax                ; EDI = offset - x
  666.   mov    dx,[xOff]
  667.   add    edi,edx                ; EDI = offset
  668.   mov    edx,edi                ; EDX = offset
  669.   shr    edx,4                ; EDX = # of paragraphs (segments)
  670.   add    dx,[outSeg]            ; DX = new segment
  671.   mov    es,dx                ; ES = new segment
  672.   and    di,0000000000001111b             ; DI = offset within new segment
  673.  
  674.   lds    si,[buf]            ; load input address
  675.   mov    dx,si                ; DX = offset
  676.   shr    dx,4                ; DX = # of paragraphs (segments)
  677.   mov    ax,ds                ; AX = DS
  678.   add    ax,dx                ; AX = new DS
  679.   mov    ds,ax                ; DS = new DS
  680.   and    si,0000000000001111b        ; SI = offset within new segment
  681.  
  682.   cld
  683.   mov    cx,[lineLen]            ; CX = line length
  684.  
  685.     @@loopStart:
  686.   lodsb                    ; grab a pixel
  687.   or    al,al                ; is it a zero pixel?
  688.   jz    @@invisible            ; yes, don't copy it
  689.   stosb                    ; no, copy it ...
  690.   loop    @@loopStart            ; ... and start loop again
  691.   jmp    short    @@loopDone        ; quit loop when completed
  692.     @@invisible:
  693.   inc    di                ; skip past pixel ...
  694.   loop    @@loopStart            ; ... and start loop again
  695.  
  696.     @@loopDone:
  697.   pop    di si ds            ; restore registers
  698.   leave                    ; clean up
  699.   retf                    ; return
  700. ENDP
  701.  
  702.  
  703. ;*****
  704. ;***** getLine
  705. ;*****
  706.  
  707. PROC    C    getLine_scr
  708.     ARG    y:WORD, xOff:WORD, lineLen:WORD, buf:DWORD
  709.   push    ds si di
  710.  
  711.   cld
  712.   mov    bx,[y]                ; Decide if bank changes mid-line
  713.   shl    bx,1
  714.   cmp    [cs:bankChanges+bx],0
  715.   jne    @@BankChanged
  716.  
  717.   mov    ax,[cs:bankNum+bx]
  718.   cmp    ax,[curBank]            ; set bank only if necessary
  719.   je    @@NoNewBank
  720.   NEWBANK
  721.  
  722.     @@NoNewBank:
  723.   mov    cx,[lineLen]            ; blast the line into video memory
  724.   mov    ax,0A000h
  725.   mov    ds,ax
  726.   mov    si,[cs:lineOffs+bx]
  727.   add    si,[xOff]
  728.   les    di,[buf]
  729.   mov    dx,cx                ; DX = CX
  730.   shr    cx,2                ; CX = line length in dwords
  731.   rep    movsd                ; copy the dwords
  732.   mov    cx,dx                ; CX = line length in bytes
  733.   and    cx,0000000000000011b        ; CX = number of residual bytes
  734.   rep    movsb                ; copy the residual bytes, if any
  735.   pop    di si ds            ; restore registers
  736.   leave                        ; clean up call stack
  737.   retf                    ; return
  738.  
  739.     @@BankChanged:                  ; slow pixel-by-pixel
  740.   mov    cx,[lineLen]
  741.   mov    dx,[y]
  742.   mov    bx,[xOff]
  743.   les    di,[buf]
  744.     @@Loop:
  745.   push    bx cx dx di es
  746.   call    far getPixel_scr C,bx,dx
  747.   pop    es di dx cx bx
  748.   stosb
  749.   inc    bx
  750.   loop    @@Loop
  751.  
  752.   pop    di si ds
  753.   leave
  754.   retf
  755. ENDP
  756.  
  757. PROC    C    getLine_mem
  758.     ARG    y:WORD, xOff:WORD, lineLen:WORD, buf:DWORD
  759.   push    ds si di            ; save these registers
  760.  
  761.   xor    eax,eax                ; clear EAX
  762.   xor    edx,edx                ; clear EDX
  763.   xor    esi,esi                ; clear ESI
  764.  
  765.   les    si,[inAddr]            ; load input address
  766.   mov    ax,[y]
  767.   mov    dx,[inScreenWide]
  768.   mul    edx                    ; EDX:EAX = offset - ESI - x
  769.   add    esi,eax                ; ESI = offset - x
  770.   mov    dx,[xOff]
  771.   add    esi,edx                ; ESI = offset
  772.   mov    edx,esi                ; EDX = offset
  773.   shr    edx,4                ; EDX = # of paragraphs (segments)
  774.   add    dx,[inSeg]            ; DX = new segment
  775.   mov    ds,dx                ; ES = new segment
  776.   and    si,0000000000001111b             ; SI = offset within new segment
  777.  
  778.   les    di,[buf]            ; load output address
  779.   mov    dx,di                ; DX = offset
  780.   shr    dx,4                ; DX = # of paragraphs (segments)
  781.   mov    ax,es                ; AX = ES
  782.   add    ax,dx                ; AX = new ES
  783.   mov    es,ax                ; ES = new ES
  784.   and    di,0000000000001111b        ; DI = offset within new segment
  785.  
  786.   cld
  787.   mov    cx,[lineLen]            ; CX = line length
  788.   mov    dx,cx                ; DX = line length
  789.   shr    cx,2                ; CX = line length in dwords
  790.   rep    movsd                     ; move the dwords if necessary
  791.   mov    cx,dx                ; CX = line length in bytes
  792.   and    cx,0000000000000011b        ; CX = any residual bytes
  793.   rep    movsb                ; move the bytes if necessary
  794.  
  795.   pop    di si ds            ; restore registers
  796.   leave                    ; clean up
  797.   retf                    ; return
  798. ENDP
  799.  
  800.  
  801. ;*****
  802. ;***** putPixel
  803. ;*****
  804.  
  805. ; Copy a pixel to the screen
  806. PROC    C    putPixel_scr_copy
  807.     ARG    x:WORD, y:WORD, colour:BYTE
  808.   mov    bx,[y]                ; BX = y coordinate
  809.   shl    bx,1                ; to access a table of words
  810.   mov    ax,[cs:bankNum+bx]        ; AX = bank at start of line
  811.   mov    bx,[cs:lineOffs+bx]        ; DX = offset at start of line
  812.   add    bx,[x]                ; BX = offset of pixel
  813.   adc    ax,0                ; in case of overflow, inc AX
  814.   mov    dx,[bksizeShl10Dec]        ; DX = bank size in bytes - 1
  815.   cmp    bx,dx                ; is offset > than bank size
  816.   jbe    @@offsetOK            ; no, proceed
  817.  
  818.   sub    bx,dx                ; BX = fixed offset
  819.   inc    ax                ; AX = new bank
  820.  
  821.     @@offsetOK:
  822.   cmp    ax,[curBank]
  823.   je    @@NoNew
  824.   NEWBANK                ; switch banks if a new bank entered
  825.     @@NoNew:
  826.   mov    ax,0A000h            ; setup screen segment A000
  827.   mov    es,ax
  828.   mov    al,[colour]            ; get color of pixel to plot
  829.   mov    [es:bx],al
  830.   leave
  831.   retf
  832. ENDP
  833.  
  834. ; Copy a pixel to memory
  835. PROC    C    putPixel_mem_copy
  836.     ARG    x:WORD,y:WORD,colour:BYTE
  837.   xor    eax,eax                ; clear EAX
  838.   xor    ebx,ebx                ; clear EBX
  839.   xor    edx,edx                ; clear EDX
  840.  
  841.   les    bx,[outAddr]            ; load output address
  842.   mov    ax,[y]
  843.   mov    dx,[outScreenWide]
  844.   mul    edx                    ; EDX:EAX = offset - EBX - x
  845.   add    ebx,eax                ; EBX = offset - x
  846.   mov    dx,[x]
  847.   add    ebx,edx                ; EBX = offset
  848.  
  849.   mov    edx,ebx                ; EDX = offset
  850.   shr    edx,4                ; EDX = # of paragraphs (segments)
  851.   add    dx,[outSeg]            ; DX = new segment
  852.   mov    es,dx                ; ES = new segment
  853.   and    bx,0000000000001111b             ; BX = offset within new segment
  854.  
  855.   mov    al,[colour]            ; colour in AL
  856.   mov    [es:bx],al            ; store pixel
  857.   leave                    ; clean up
  858.   retf                    ; return
  859. ENDP
  860.  
  861. ; AND a pixel to memory
  862. PROC    C    putPixel_mem_and
  863.     ARG    x:WORD,y:WORD,colour:BYTE
  864.   xor    eax,eax                ; clear EAX
  865.   xor    ebx,ebx                ; clear EBX
  866.   xor    edx,edx                ; clear EDX
  867.  
  868.   les    bx,[outAddr]            ; load output address
  869.   mov    ax,[y]
  870.   mov    dx,[outScreenWide]
  871.   mul    edx                    ; EDX:EAX = offset - EBX - x
  872.   add    ebx,eax                ; EBX = offset - x
  873.   mov    dx,[x]
  874.   add    ebx,edx                ; EBX = offset
  875.  
  876.   mov    edx,ebx                ; EDX = offset
  877.   shr    edx,4                ; EDX = # of paragraphs (segments)
  878.   add    dx,[outSeg]            ; DX = new segment
  879.   mov    es,dx                ; ES = new segment
  880.   and    bx,0000000000001111b             ; BX = offset within new segment
  881.  
  882.   mov    al,[colour]            ; colour in AL
  883.   and    [es:bx],al            ; AND pixel
  884.   leave                    ; clean up
  885.   retf                    ; return
  886. ENDP
  887.  
  888. ; NOT a pixel to memory
  889. PROC    C    putPixel_mem_not
  890.     ARG    x:WORD,y:WORD,colour:BYTE
  891.   xor    eax,eax                ; clear EAX
  892.   xor    ebx,ebx                ; clear EBX
  893.   xor    edx,edx                ; clear EDX
  894.  
  895.   les    bx,[outAddr]            ; load output address
  896.   mov    ax,[y]
  897.   mov    dx,[outScreenWide]
  898.   mul    edx                    ; EDX:EAX = offset - EBX - x
  899.   add    ebx,eax                ; EBX = offset - x
  900.   mov    dx,[x]
  901.   add    ebx,edx                ; EBX = offset
  902.  
  903.   mov    edx,ebx                ; EDX = offset
  904.   shr    edx,4                ; EDX = # of paragraphs (segments)
  905.   add    dx,[outSeg]            ; DX = new segment
  906.   mov    es,dx                ; ES = new segment
  907.   and    bx,0000000000001111b             ; BX = offset within new segment
  908.  
  909.   mov    al,[colour]            ; colour in AL
  910.   not    al                ; NOT it
  911.   mov    [es:bx],al            ; store NOTed pixel
  912.   leave                    ; clean up
  913.   retf                    ; return
  914. ENDP
  915.  
  916. ; OR a pixel to memory
  917. PROC    C    putPixel_mem_or
  918.     ARG    x:WORD,y:WORD,colour:BYTE
  919.   xor    eax,eax                ; clear EAX
  920.   xor    ebx,ebx                ; clear EBX
  921.   xor    edx,edx                ; clear EDX
  922.  
  923.   les    bx,[outAddr]            ; load output address
  924.   mov    ax,[y]
  925.   mov    dx,[outScreenWide]
  926.   mul    edx                    ; EDX:EAX = offset - EBX - x
  927.   add    ebx,eax                ; EBX = offset - x
  928.   mov    dx,[x]
  929.   add    ebx,edx                ; EBX = offset
  930.  
  931.   mov    edx,ebx                ; EDX = offset
  932.   shr    edx,4                ; EDX = # of paragraphs (segments)
  933.   add    dx,[outSeg]            ; DX = new segment
  934.   mov    es,dx                ; ES = new segment
  935.   and    bx,0000000000001111b             ; BX = offset within new segment
  936.  
  937.   mov    al,[colour]            ; colour in AL
  938.   or    [es:bx],al            ; OR pixel
  939.   leave                    ; clean up
  940.   retf                    ; return
  941. ENDP
  942.  
  943. ; XOR a pixel to memory
  944. PROC    C    putPixel_mem_xor
  945.     ARG    x:WORD,y:WORD,colour:BYTE
  946.   xor    eax,eax                ; clear EAX
  947.   xor    ebx,ebx                ; clear EBX
  948.   xor    edx,edx                ; clear EDX
  949.  
  950.   les    bx,[outAddr]            ; load output address
  951.   mov    ax,[y]
  952.   mov    dx,[outScreenWide]
  953.   mul    edx                    ; EDX:EAX = offset - EBX - x
  954.   add    ebx,eax                ; EBX = offset - x
  955.   mov    dx,[x]
  956.   add    ebx,edx                ; EBX = offset
  957.  
  958.   mov    edx,ebx                ; EDX = offset
  959.   shr    edx,4                ; EDX = # of paragraphs (segments)
  960.   add    dx,[outSeg]            ; DX = new segment
  961.   mov    es,dx                ; ES = new segment
  962.   and    bx,0000000000001111b             ; BX = offset within new segment
  963.  
  964.   mov    al,[colour]            ; colour in AL
  965.   xor    [es:bx],al            ; XOR pixel
  966.   leave                    ; clean up
  967.   retf                    ; return
  968. ENDP
  969.  
  970.  
  971. ;*****
  972. ;***** getPixel
  973. ;*****
  974.  
  975. ; Get a pixel from the screen
  976. PROC    C    getPixel_scr
  977.     ARG    x:WORD, y:WORD
  978.   mov    bx,[y]                ; BX = y coordinate
  979.   shl    bx,1                ; to access a table of words
  980.   mov    ax,[cs:bankNum+bx]        ; AX = bank at start of line
  981.   mov    bx,[cs:lineOffs+bx]        ; DX = offset at start of line
  982.   add    bx,[x]                ; BX = offset of pixel
  983.   adc    ax,0                ; in case of overflow, inc AX
  984.   mov    dx,[bksizeShl10Dec]        ; DX = bank size in bytes - 1
  985.   cmp    bx,dx                ; is offset > than bank size
  986.   jb    @@offsetOK            ; no, proceed
  987.  
  988.   sub    bx,dx                ; BX = fixed offset
  989.   inc    ax                ; AX = new bank
  990.  
  991.     @@offsetOK:
  992.   cmp    ax,[curBank]
  993.   je    @@NoNew
  994.   NEWBANK                ; switch banks if a new bank entered
  995.     @@NoNew:
  996.   mov    ax,0A000h            ; setup screen segment A000
  997.   mov    es,ax
  998.   mov    al,[es:bx]            ; AL = colour for return
  999.   leave
  1000.   retf
  1001. ENDP
  1002.  
  1003. ; Get a pixel from memory
  1004. PROC    C    getPixel_mem
  1005.     ARG    x:WORD,y:WORD
  1006.   xor    eax,eax                ; clear EAX
  1007.   xor    ebx,ebx                ; clear EBX
  1008.   xor    edx,edx                ; clear EDX
  1009.  
  1010.   les    bx,[inAddr]            ; load input address
  1011.   mov    ax,[y]
  1012.   mov    dx,[inScreenWide]
  1013.   mul    edx                    ; EDX:EAX = offset - EBX - x
  1014.   add    ebx,eax                ; EBX = offset - x
  1015.   mov    dx,[x]
  1016.   add    ebx,edx                ; EBX = offset
  1017.  
  1018.   mov    edx,ebx                ; EDX = offset
  1019.   shr    edx,4                ; EDX = # of paragraphs (segments)
  1020.   add    dx,[inSeg]            ; DX = new segment
  1021.   mov    es,dx                ; ES = new segment
  1022.   and    bx,0000000000001111b             ; BX = offset within new segment
  1023.  
  1024.   xor    ax,ax                ; clear AX
  1025.   mov    al,[es:bx]            ; store pixel in AX for return
  1026.   leave                    ; clean up
  1027.   retf                    ; return
  1028. ENDP
  1029.  
  1030.  
  1031. ;*****
  1032. ;***** horizLine
  1033. ;*****
  1034.  
  1035. PROC    C    horizLine_scr_copy
  1036.     ARG    y:WORD, x1:WORD, x2:WORD, colour:BYTE
  1037.   push    di
  1038.  
  1039.   cld
  1040.   mov    bx,[y]                ; Decide if bank changes mid-line
  1041.   shl    bx,1
  1042.   cmp    [cs:bankChanges+bx],0
  1043.   jne    @@BankChanged
  1044.  
  1045.   mov    ax,[cs:bankNum+bx]
  1046.   cmp    ax,[curBank]            ; set bank only if necessary
  1047.   je    @@NoNewBank
  1048.   NEWBANK
  1049.  
  1050.     @@NoNewBank:
  1051.   mov    ax,0A000h
  1052.   mov    es,ax
  1053.   mov    ax,[x1]
  1054.   mov    di,[cs:lineOffs+bx]
  1055.   add    di,ax
  1056.   mov    cx,[x2]                ; blast the line into video memory
  1057.   inc    cx
  1058.   sub    cx,ax
  1059.   mov    al,[colour]            ; AL = colour
  1060.   mov    ah,al                ; AH = colour
  1061.   mov    dx,ax                ; DX = colour:colour
  1062.   shl    eax,16                ; EAX = colour:colour:?:?
  1063.   mov    ax,dx                ; EAX = colour:colour:colour:colour
  1064.   mov    dx,cx                ; DX = CX
  1065.   shr    cx,2                ; CX = line length in dwords
  1066.   rep    stosd                ; store the dwords
  1067.   mov    cx,dx                ; CX = line length in bytes
  1068.   and    cx,0000000000000011b        ; CX = number of residual bytes
  1069.   rep    stosb                ; store the residual bytes, if any
  1070.   pop    di                ; restore DI
  1071.   leave                    ; clean up call stack
  1072.   retf                    ; return
  1073.  
  1074.     @@BankChanged:                  ; slow pixel-by-pixel
  1075.   mov    bx,[x1]
  1076.   mov    cx,[x2]
  1077.   inc    cx
  1078.   sub    cx,bx
  1079.   mov    dx,[y]
  1080.     @@Loop:
  1081.   push    bx cx dx
  1082.   mov    al,[colour]
  1083.   call    far putPixel_scr_copy C,bx,dx,ax
  1084.   pop    dx cx bx
  1085.   inc    bx
  1086.   loop    @@Loop
  1087.  
  1088.   pop    di
  1089.   leave
  1090.   retf
  1091. ENDP
  1092.  
  1093. PROC    C    horizLine_mem_copy
  1094.     ARG    y:WORD, x1:WORD, x2:WORD, colour:BYTE
  1095.   push    edi                ; store EDI
  1096.  
  1097.   xor    eax,eax                ; clear EAX
  1098.   xor    edi,edi                ; clear EDI
  1099.   xor    edx,edx                ; clear EDX
  1100.  
  1101.   les    di,[outAddr]            ; load output address
  1102.   mov    ax,[y]
  1103.   mov    dx,[outScreenWide]
  1104.   mul    edx                    ; EDX:EAX = offset - EDI - x
  1105.   add    edi,eax                ; EDI = offset - x
  1106.   mov    dx,[x1]
  1107.   add    edi,edx                ; EDI = offset
  1108.   mov    edx,edi                ; EDX = offset
  1109.   shr    edx,4                ; EDX = # of paragraphs (segments)
  1110.   add    dx,[outSeg]            ; DX = new segment
  1111.   mov    es,dx                ; ES = new segment
  1112.   and    di,0000000000001111b             ; DI = offset within new segment
  1113.  
  1114.   mov    al,[colour]            ; colour in AL
  1115.   mov    ah,al                ; colour in AH
  1116.   mov    bx,ax
  1117.   shl    eax,16
  1118.   mov    ax,bx                 ; colour in each byte of EAX
  1119.  
  1120.   mov    cx,[x2]
  1121.   sub    cx,[x1]
  1122.   inc    cx                ; CX = line length in pixels
  1123.   mov    dx,cx                ; DX = line length in bytes
  1124.  
  1125.   shr    cx,2                ; CX = line length in dwords
  1126.   rep    stosd                ; store four bytes at a time
  1127.   mov    cx,dx                ; CX = line length in pixels
  1128.   and    cx,0000000000000011b        ; CX = any remaining bytes
  1129.   rep    stosb                ; store the remaining bytes
  1130.  
  1131.   pop    edi                    ; restore EDI
  1132.   leave                    ; clean up
  1133.   retf                    ; return
  1134. ENDP
  1135.  
  1136.  
  1137. ;*****
  1138. ;***** setPaletteReg
  1139. ;*****
  1140.  
  1141. PROC    C    setPaletteReg
  1142.     ARG    palNum:WORD,red:BYTE,green:BYTE,blue:BYTE
  1143.   mov    bx,[palNum]
  1144.  
  1145.   mov    dx,3C8h                ; set for correct palette register
  1146.   mov    ax,[palNum]
  1147.   out    dx,al
  1148.   inc    dx
  1149.  
  1150.   mov    al,[red]            ; red
  1151.   shr    al,2
  1152.   jnc    @@L1
  1153.   cmp    al,63
  1154.   je    @@L1
  1155.   inc    al
  1156.     @@L1:
  1157.   out    dx,al
  1158.  
  1159.   mov    al,[green]            ; green
  1160.   shr    al,2
  1161.   jnc    @@L2
  1162.   cmp    al,63
  1163.   je    @@L2
  1164.   inc    al
  1165.     @@L2:
  1166.   out    dx,al
  1167.  
  1168.   mov    al,[blue]            ; blue
  1169.   shr    al,2
  1170.   jnc    @@L3
  1171.   cmp    al,63
  1172.   je    @@L3
  1173.   inc    al
  1174.     @@L3:
  1175.   out    dx,al
  1176.  
  1177.   leave
  1178.   retf
  1179. ENDP
  1180.  
  1181.  
  1182. ;*****
  1183. ;***** getPaletteReg
  1184. ;*****
  1185.  
  1186. PROC    C    getPaletteReg
  1187.     ARG    palNum:WORD,red:DWORD,green:DWORD,blue:DWORD
  1188.   push    ds si
  1189.  
  1190.   mov    dx,3C7h                ; set for correct palette register
  1191.   mov    ax,[palNum]
  1192.   out    dx,al
  1193.   mov    dx,3C9h
  1194.  
  1195.   in    al,dx                ; red
  1196.   lds    si,[red]
  1197.   shl    al,2
  1198.   mov    [ds:si],al
  1199.   in    al,dx                ; green
  1200.   lds    si,[green]
  1201.   shl    al,2
  1202.   mov    [ds:si],al
  1203.   in    al,dx                ; blue
  1204.   lds    si,[blue]
  1205.   shl    al,2
  1206.   mov    [ds:si],al
  1207.  
  1208.   pop    si ds
  1209.   leave
  1210.   retf
  1211. ENDP
  1212.  
  1213.  
  1214. ;*****
  1215. ;***** setBlockPalette
  1216. ;*****
  1217.  
  1218.     PUBLIC    C    setBlockPalette
  1219. PROC    C    setBlockPalette
  1220.     ARG    firstReg:WORD,lastReg:WORD,paletteData:DWORD
  1221.   push    ds si
  1222.  
  1223.   lds    si,[paletteData]        ; set up
  1224.   mov    dx,3C8h
  1225.   mov    ax,[firstReg]
  1226.   out    dx,al
  1227.   inc    dx
  1228.   mov    cx,[lastReg]            ; CX = number of registers
  1229.   sub    cx,ax
  1230.   inc    cx
  1231.   cld
  1232.  
  1233.     @@LLoop:
  1234.   lodsb            ; red
  1235.   shr    al,2
  1236.   jnc    @@L1
  1237.   cmp    al,63
  1238.   je    @@L1
  1239.   inc    al
  1240.     @@L1:
  1241.   out    dx,al
  1242.  
  1243.   lodsb            ; green
  1244.   shr    al,2
  1245.   jnc    @@L2
  1246.   cmp    al,63
  1247.   je    @@L2
  1248.   inc    al
  1249.     @@L2:
  1250.   out    dx,al
  1251.  
  1252.   lodsb            ; blue
  1253.   shr    al,2
  1254.   jnc    @@L3
  1255.   cmp    al,63
  1256.   je    @@L3
  1257.   inc    al
  1258.     @@L3:
  1259.   out    dx,al
  1260.  
  1261.   loop    @@LLoop
  1262.  
  1263.     @@LExit:
  1264.   pop    si ds
  1265.   leave
  1266.   retf
  1267. ENDP
  1268.  
  1269.  
  1270. ;*****
  1271. ;***** getBlockPalette
  1272. ;*****
  1273.  
  1274.     PUBLIC    C    getBlockPalette
  1275. PROC    C    getBlockPalette
  1276.     ARG    firstReg:WORD,lastReg:WORD,paletteData:DWORD
  1277.   push    di
  1278.  
  1279.   les    di,[paletteData]        ; set up
  1280.   mov    dx,3C7h
  1281.   mov    ax,[firstReg]
  1282.   out    dx,al
  1283.   mov    dx,3C9h
  1284.   mov    cx,[lastReg]            ; CX = number of registers
  1285.   sub    cx,ax
  1286.   inc    cx
  1287.   cld
  1288.  
  1289.     @@L1:
  1290.   in    al,dx
  1291.   shl    al,2
  1292.   stosb            ; red
  1293.   in    al,dx
  1294.   shl    al,2
  1295.   stosb            ; green
  1296.   in    al,dx
  1297.   shl    al,2
  1298.   stosb            ; blue
  1299.   loop    @@L1
  1300.  
  1301.     @@LExit:
  1302.   pop    di
  1303.   leave
  1304.   retf
  1305. ENDP
  1306.  
  1307.  
  1308. ;*****
  1309. ;***** Bank switching routines
  1310. ;*****
  1311.  
  1312. _aheadb:                ; Ahead Systems Ver B
  1313.   push    ax dx cx
  1314.   cli
  1315.   mov    [curBank],ax
  1316.   mov    ch,al
  1317.   mov    dx,3CEh            ; Enable extended registers
  1318.   mov    ax,200Fh
  1319.   out    dx,ax
  1320.   mov    ah,ch
  1321.   mov    cl,4
  1322.   shl    ah,cl
  1323.   or    ah,ch
  1324.   mov    al,0Dh
  1325.   out    dx,ax
  1326.   sti
  1327.   pop    cx dx ax
  1328.   ret
  1329.  
  1330. _ativga:                ; ATI VGA Wonder
  1331.   push    ax dx
  1332.   cli
  1333.   mov    [curBank],ax
  1334.   mov    ah,al
  1335.   mov    dx,1CEh
  1336.   mov    al,0B2h
  1337.   out    dx,al
  1338.   inc    dl
  1339.   in    al,dx
  1340.   shl    ah,1
  1341.   and    al,0E1h
  1342.   or    ah,al
  1343.   mov    al,0B2h
  1344.   dec    dl
  1345.   out    dx,ax
  1346.   sti
  1347.   pop    dx ax
  1348.   ret
  1349.  
  1350. _chipstech:                ; Chips & Tech
  1351.   push    ax dx ax
  1352.   cli
  1353.   mov    [curBank],ax
  1354.   mov    dx,46E8h        ; place chip in setup mode
  1355.   mov    ax,1Eh
  1356.   out    dx,ax
  1357.   mov    dx,103h            ; enable extended registers
  1358.   mov    ax,0080h
  1359.   out    dx,ax
  1360.   mov    dx,46E8h        ; bring chip out of setup mode
  1361.   mov    ax,0Eh
  1362.   out    dx,ax
  1363.   pop    ax
  1364.   mov    ah,al
  1365.   mov    al,10h
  1366.   mov    dx,3D6h
  1367.   out    dx,ax
  1368.   sti
  1369.   pop    dx ax
  1370.   ret
  1371.  
  1372. _everex:                ; Everex
  1373.   push    ax dx cx
  1374.   cli
  1375.   mov    [curBank],ax
  1376.   mov    cl,al
  1377.   mov    dx,3C4h
  1378.   mov    al,8
  1379.   out    dx,al
  1380.   inc    dl
  1381.   in    al,dx
  1382.   dec    dl
  1383.   shl    al,1
  1384.   shr    cl,1
  1385.   rcr    al,1
  1386.   mov    ah,al
  1387.   mov    al,8
  1388.   out    dx,ax
  1389.   mov    dl,0CCh
  1390.   in    al,dx
  1391.   mov    dl,0C2h
  1392.   and    al,0DFh
  1393.   shr    cl,1
  1394.   jc    @@nob2
  1395.   or    al,20h
  1396.       @@nob2:
  1397.   out    dx,al
  1398.   sti
  1399.   pop    cx dx ax
  1400.   ret
  1401.  
  1402. _oak067:                ; Oak Technology Inc OTI-067
  1403.   push    ax dx
  1404.   cli
  1405.   mov    [curBank],ax
  1406.   and    al,15
  1407.   mov    ah,al
  1408.   shl    al,4
  1409.   or    ah,al
  1410.   mov    al,11h
  1411.   mov    dx,3DEh
  1412.   out    dx,ax
  1413.   sti
  1414.   pop    dx ax
  1415.   ret
  1416.  
  1417. _t8900:                    ; Trident 8900
  1418.   push    ax dx ax
  1419.   cli
  1420.   mov    [curBank],ax
  1421.   mov    dx,3CEh            ; set pagesize to 64k
  1422.   mov    al,6
  1423.   out    dx,al
  1424.   inc    dl
  1425.   in    al,dx
  1426.   dec    dl
  1427.   or    al,4
  1428.   mov    ah,al
  1429.   mov    al,6
  1430.   out    dx,ax
  1431.  
  1432.   mov    dl,0C4h            ; switch to BPS mode
  1433.   mov    al,0Bh
  1434.   out    dx,al
  1435.   inc    dl
  1436.   in    al,dx
  1437.   dec    dl
  1438.  
  1439.   pop    ax
  1440.   mov    ah,al
  1441.   xor    ah,2
  1442.   mov    dx,3C4h
  1443.   mov    al,0Eh
  1444.   out    dx,ax
  1445.   sti
  1446.   pop    dx ax
  1447.   ret
  1448.  
  1449. _tseng4:                ; Tseng 4000 series
  1450.   push    ax dx
  1451.   cli
  1452.   mov    [curBank],ax
  1453.   mov    ah,al
  1454.   mov    dx,3BFh            ; Enable access to extended registers
  1455.   mov    al,3
  1456.   out    dx,al
  1457.   mov    dl,0D8h
  1458.   mov    al,0A0h
  1459.   out    dx,al
  1460.   and    ah,15
  1461.   mov    al,ah
  1462.   shl    al,4
  1463.   or    al,ah
  1464.   mov    dl,0CDh
  1465.   out    dx,al
  1466.   sti
  1467.   pop    dx ax
  1468.   ret
  1469.  
  1470. _vesa:                ; Vesa SVGA interface
  1471.   push    ax bx dx
  1472.   cli
  1473.   mov    [curBank],ax
  1474.   mov    dx,ax
  1475.   xor    bx,bx
  1476.   mov    ax,4F05h
  1477.   int    10h
  1478.   sti
  1479.   pop    dx bx ax
  1480.   ret
  1481.  
  1482. _nobank:
  1483.   cli
  1484.   mov    [curBank],ax
  1485.   sti
  1486.   ret
  1487.  
  1488.  
  1489. MACRO    BKADR    func
  1490.   mov    [func],1
  1491.   mov    [bankadr],OFFSET _&func
  1492. ENDM
  1493.  
  1494. MACRO    NOJMP
  1495.   local    lbl
  1496.   jmp    short    lbl
  1497.     lbl:
  1498. ENDM
  1499.  
  1500.  
  1501. PROC    whichVGA    NEAR
  1502.   push    si di
  1503.  
  1504.   cmp    [inited],1
  1505.   jne    @@goTest
  1506.   mov    ax,[retval]
  1507.   pop    di si
  1508.   ret
  1509.  
  1510.     @@goTest:
  1511.   mov    [bankadr],OFFSET _nobank
  1512.   mov    [vgamem],256
  1513.   mov    [bksize],64
  1514.   xor    ax,ax
  1515.   mov    [curBank],ax
  1516.   mov    [aheadb],ax
  1517.   mov    [ativga],ax
  1518.   mov    [everex],ax
  1519.   mov    [t8900],ax
  1520.   mov    [tseng4],ax
  1521.   mov    [vesa],ax
  1522.  
  1523.   mov    si,1                ; success code; changed on error
  1524.  
  1525.   mov    ax,cs                ; Test for VESA
  1526.   mov    es,ax
  1527.   mov    di,OFFSET vesabuf
  1528.   mov    ax,4F00h
  1529.   int    10h
  1530.   cmp    ax,004Fh
  1531.   jne    @@noVESA
  1532.   BKADR    vesa
  1533.   mov    [bksize],64            ; assume 64 K bank size (for now)
  1534.   mov    [vgamem],1024            ; assume 1024 K if VESA
  1535.   jmp    @@fini
  1536.  
  1537.     @@noVESA:
  1538.   mov    ax,0C000h            ; Test for ATI
  1539.   mov    es,ax
  1540.   cmp    [word ptr es:40h],'13'    ; ATI Signiture on the Video BIOS
  1541.   jnz    @@noATI
  1542.   BKADR    ativga
  1543.   mov    [bksize],64        ; 64K bank size
  1544.   mov    dx,[es:10h]        ; get value of ATI extended register
  1545.   mov    bl,[es:43h]        ; get value of ATI chip version
  1546.   cmp    bl,'3'
  1547.   jae    @@v6up            ; use different method to find memory size
  1548.   mov    al,0BBh
  1549.   cli
  1550.   out    dx,al
  1551.   inc    dx
  1552.   in    al,dx
  1553.   sti
  1554.   test    al,20h
  1555.   jz    @@no512
  1556.   mov    [vgamem],512
  1557.   jmp    short    @@no512
  1558.       @@v6up:
  1559.   mov    al,0B0h            ; method for newer ATIs
  1560.   cli
  1561.   out    dx,al
  1562.   inc    dx
  1563.   in    al,dx            ; get RAM size for versions 3-5
  1564.   sti
  1565.   test    al,10h            ; check if 256 K or 512 K
  1566.   jz    @@v7up
  1567.   mov    [vgamem],512
  1568.       @@v7up:
  1569.   cmp    bl,'4'            ; get RAM size for versions 4 & 5
  1570.   jb    @@no512
  1571.   test    al,8            ; check if version 5 chip has 1024 K
  1572.   jz    @@no512
  1573.   mov    [vgamem],1024
  1574.       @@no512:
  1575.   jmp    @@fini
  1576.  
  1577.     @@noATI:
  1578.   mov    ax,7000h            ; Test for Everex
  1579.   xor    bx,bx
  1580.   cld
  1581.   int    10h
  1582.   cmp    al,70h
  1583.   jnz    @@noEverex
  1584.   BKADR    everex
  1585.   mov    [bksize],64        ; 64 K bank size
  1586.   and    ch,10000000b        ; how much memory on board?
  1587.   jz    @@skp
  1588.   mov    [vgamem],1024
  1589.      @@skp:            ; fall through for Everex boards using Trident or Tseng4000
  1590.  
  1591.     @@noEverex:
  1592.   mov    ax,5F00h            ; Test for Chips & Tech
  1593.   xor    bx,bx
  1594.   cld
  1595.   int    10h
  1596.   cmp    al,5Fh
  1597.   jnz    @@noChipsTech
  1598.   BKADR    chipstech
  1599.   mov    [bksize],16        ; 16 K bank size
  1600.   cmp    bh,2
  1601.   jb    @@skp4
  1602.   mov    [vgamem],1024
  1603.     @@skp4:
  1604.   jmp    @@fini
  1605.  
  1606.     @@noChipsTech:
  1607.   mov    dx,3DEh                ; Test for Oak Technology
  1608.   mov    ax,0FF11h        ; look for bank switch register
  1609.   call    _isport2
  1610.   jnz    @@noOak
  1611.   BKADR    oak067
  1612.   mov    [bksize],64        ; 64 K bank size
  1613.   mov    al,0Dh
  1614.   out    dx,al
  1615.   inc    dx
  1616.   NOJMP
  1617.   in    al,dx
  1618.   test    al,11000000b
  1619.   jz    @@no4ram
  1620.   mov    [vgamem],512
  1621.   test    al,01000000b
  1622.   jz    @@no4ram
  1623.   mov    [vgamem],1024
  1624.       @@no4ram:
  1625.   jmp    @@fini
  1626.  
  1627.     @@noOak:
  1628.   mov    dx,3C4h                  ; Test for Trident
  1629.   mov    al,0Bh
  1630.   out    dx,al
  1631.   inc    dl
  1632.   in    al,dx
  1633.   and    al,0Fh
  1634.   cmp    al,06h
  1635.   ja    @@noTrident8900
  1636.   cmp    al,3
  1637.   jb       @@noTrident8900
  1638.   BKADR    t8900            ; Trident 8900 found
  1639.   mov    [bksize],64
  1640.   mov    dx,3D5h
  1641.   mov    al,1Fh
  1642.   out    dx,al
  1643.   inc    dx
  1644.   in    al,dx
  1645.   and    al,3
  1646.   cmp    al,1
  1647.   jb    @@notmem
  1648.   mov    [vgamem],512
  1649.   je    @@notmem
  1650.   mov    [vgamem],1024
  1651.     @@notmem:
  1652.   jmp    @@fini
  1653.  
  1654.     @@noTrident8900:
  1655.   xor    ch,ch                ; check for Tseng 4000 series
  1656.   mov    dx,3D4h
  1657.   mov    ax,0F33h
  1658.   call    _isport2
  1659.   jnz    @@noTseng4
  1660.   mov    ch,1
  1661.  
  1662.   mov    dx,3BFh            ; Enable access to extended registers
  1663.   mov    al,3
  1664.   out    dx,al
  1665.   mov    dx,3D8h
  1666.   mov    al,0A0h
  1667.   out    dx,al
  1668.   jmp    short @@yes4
  1669.  
  1670.     @@noTseng4:
  1671.   mov    dx,3D4h            ; Test for Tseng 3000 or 4000
  1672.   mov    ax,1F25h        ; is the Overflow High register there?
  1673.   call    _isport2
  1674.   jnz    @@noTseng
  1675.   mov    al,03Fh            ; bottom six bits only
  1676.   jmp    short @@yes3
  1677.     @@yes4:
  1678.   mov    al,0FFh
  1679.     @@yes3:
  1680.   mov    dx,3CDh            ; test bank switch register
  1681.   call    _isport1
  1682.   jnz    @@noTseng
  1683.   mov    [bksize],64        ; 64 K bank size
  1684.   or    ch,ch
  1685.   jnz    @@t4mem
  1686.   mov    [vgamem],512
  1687.   jmp    @@fini
  1688.  
  1689.     @@t4mem:
  1690.   mov    dx,3D4h            ; Tseng 4000 memory detect 1meg
  1691.   mov    al,37h
  1692.   out    dx,al
  1693.   inc    dx
  1694.   in    al,dx
  1695.   test    al,1000b        ; if using 64kx4 RAMs then no more than 256k
  1696.   jz    @@nomem
  1697.   and    al,3
  1698.   cmp    al,1            ; if 8 bit wide bus then only two 256kx4 RAMs
  1699.   jbe    @@nomem
  1700.   mov    [vgamem],512
  1701.   cmp    al,2            ; if 16 bit wide bus then four 256kx4 RAMs
  1702.   je    @@nomem
  1703.   mov    [vgamem],1024        ; full meg with eight 256kx4 RAMs
  1704.     @@nomem:
  1705.   BKADR    tseng4
  1706.   mov    [bksize],64        ; 64 K bank size
  1707.   jmp    @@fini
  1708.  
  1709.     @@noTseng:
  1710.   mov    dx,3CEh                ; Test for Above B chipset
  1711.   mov    ax,200Fh
  1712.   out    dx,ax
  1713.   inc    dx
  1714.   NOJMP
  1715.   in    al,dx
  1716.   cmp    al,21h
  1717.   jne    @@fini
  1718.   BKADR    aheadb
  1719.   mov    [bksize],64        ; 64 K bank size
  1720.   mov    [vgamem],512
  1721.   jmp   @@fini
  1722.  
  1723.       @@noSVGA:
  1724.   xor    si,si                ; set error flag
  1725.  
  1726.     @@fini:
  1727.   mov    ax,si                ; success code in AX for return
  1728.   mov    [retval],ax
  1729.   pop    di si
  1730.   ret
  1731. ENDP
  1732.  
  1733.  
  1734. PROC    _chkbk    NEAR            ; bank switch check routine
  1735.   mov    di,0B800h
  1736.   mov    es,di
  1737.   xor    di,di
  1738.   mov    bx,1234h
  1739.   call    _gochk
  1740.   jnz    @@badchk
  1741.   mov    bx,4321h
  1742.   call    _gochk
  1743.   jnz    @@badchk
  1744.   clc
  1745.   ret
  1746.     @@badchk:
  1747.   stc
  1748.   ret
  1749. ENDP
  1750.  
  1751.  
  1752. PROC    _gochk    NEAR
  1753.   push    si
  1754.   mov    si,bx
  1755.  
  1756.   mov    al,cl
  1757.   call    dx
  1758.   xchg    bl,[es:di]
  1759.   mov    al,ch
  1760.   call    dx
  1761.   xchg    bh,[es:di]
  1762.  
  1763.   xchg    si,bx
  1764.  
  1765.   mov    al,cl
  1766.   call    dx
  1767.   xor    bl,[es:di]
  1768.   mov    al,ch
  1769.   call    dx
  1770.   xor    bh,[es:di]
  1771.  
  1772.   xchg    si,bx
  1773.  
  1774.   mov    al,ch
  1775.   call    dx
  1776.   mov    [es:di],bh
  1777.   mov    al,cl
  1778.   call    dx
  1779.   mov    [es:di],bl
  1780.  
  1781.   xor    al,al
  1782.   call    dx
  1783.   or    si,si
  1784.   pop    si
  1785.   ret
  1786. ENDP
  1787.  
  1788.  
  1789. PROC    _isport2    NEAR        ; check for valid I/O port
  1790.                     ; AL is index, AH is bit mask
  1791.   push    bx
  1792.   mov    bx,ax
  1793.   out    dx,al
  1794.   mov    ah,al
  1795.   inc    dx
  1796.   in    al,dx
  1797.   dec    dx
  1798.   xchg    al,ah
  1799.   push    ax
  1800.   mov    ax,bx
  1801.   out    dx,ax
  1802.   out    dx,al
  1803.   mov    ah,al
  1804.   inc    dx
  1805.   in    al,dx
  1806.   dec    dx
  1807.   and    al,bh
  1808.   cmp    al,bh
  1809.   jnz    @@noport
  1810.   mov    al,ah
  1811.   xor    ah,ah
  1812.   out    dx,ax
  1813.   out    dx,al
  1814.   mov    ah,al
  1815.   inc    dx
  1816.   in    al,dx
  1817.   dec    dx
  1818.   and    al,bh
  1819.   cmp    al,0
  1820.     @@noport:
  1821.   pop    ax
  1822.   out    dx,ax
  1823.   pop    bx
  1824.   ret
  1825. ENDP
  1826.  
  1827.  
  1828. PROC    _isport1    NEAR        ; check for valid I/O port
  1829.                     ; AL is bit mask
  1830.   mov    ah,al
  1831.   in    al,dx
  1832.   push    ax
  1833.   mov    al,ah
  1834.   out    dx,al
  1835.   in    al,dx
  1836.   and    al,ah
  1837.   cmp    al,ah
  1838.   jnz    @@noport
  1839.   xor    al,al
  1840.   out    dx,al
  1841.   in    al,dx
  1842.   and    al,ah
  1843.   cmp    al,0
  1844.     @@noport:
  1845.   pop    ax
  1846.   out    dx,al
  1847.   ret
  1848. ENDP
  1849.  
  1850.  
  1851. PROC    setMode    NEAR            ; Set 1024x768x256
  1852.   mov    ax,SCREEN_WIDE
  1853.   mov    [scanline],ax
  1854.  
  1855.   cmp    [vesa],0
  1856.   jz    @@noVESA
  1857.   mov    bx,105h
  1858.   call    VESAset
  1859.   or    ax,ax                ; was function successful?
  1860.   jz    @@noSVGA            ; no, quit
  1861.   jmp    @@godo2
  1862.       @@noVESA:
  1863.   cmp    [aheadb],0
  1864.   jz    @@noAbove
  1865.   mov    ax,63h
  1866.   jmp    short @@godo
  1867.     @@noAbove:
  1868.   cmp    [everex],0
  1869.   jz    @@noEverex
  1870.   mov    ax,70h
  1871.   mov    bl,32h
  1872.   jmp    short @@godo
  1873.     @@noEverex:
  1874.   cmp    [ativga],0
  1875.   jz    @@noATI
  1876.   mov    ax,64h
  1877.   jmp    short @@godo
  1878.     @@noATI:
  1879.   cmp    [oak067],0
  1880.   jz    @@noOak067
  1881.   mov    ax,59h
  1882.   jmp    short    @@godo
  1883.       @@noOak067:
  1884.   cmp    [t8900],0
  1885.   jz    @@noTrident8900
  1886.   mov    ax,62h
  1887.   jmp    short @@godo
  1888.     @@noTrident8900:
  1889.   cmp    [tseng4],0
  1890.   jz    @@noSVGA
  1891.   mov    ax,38h
  1892.  
  1893.     @@godo:
  1894.   int    10h
  1895.       @@godo2:
  1896.   mov    [curBank],-1
  1897.   mov    ax,1                ; return success code
  1898.   ret
  1899.  
  1900.     @@noSVGA:
  1901.   xor    ax,ax                ; return error code
  1902.   ret
  1903. ENDP
  1904.  
  1905.  
  1906. PROC    VESAset        NEAR
  1907.   push    di
  1908.  
  1909.   push    bx
  1910.   mov    ax,4F02h
  1911.   int    10h                   ; set the mode
  1912.   pop    cx
  1913.   or    ah,ah                ; was function successful?
  1914.   jz    @@noError            ; yes
  1915.   xor    ax,ax                ; set error code (for setMode)
  1916.   jmp    short    @@Exit
  1917.  
  1918.       @@noError:
  1919.   mov    ax,cs
  1920.   mov    es,ax
  1921.   mov    di,OFFSET modebuf
  1922.   mov    ax,4F01h
  1923.   int    10h                ; get the mode information
  1924.   mov    ax,[modebuf.WinSize]
  1925.   mov    [bksize],ax
  1926.   mov    ax,[modebuf.BytesPerLine]
  1927.   mov    [scanline],ax
  1928.   mov    ax,1                ; set success code (for setMode)
  1929.  
  1930.       @@Exit:
  1931.   pop    di
  1932.   ret
  1933. ENDP
  1934.  
  1935.  
  1936. PROC    makeAddrTable    NEAR
  1937.   LOCAL    temp:WORD
  1938.   push    si di
  1939.  
  1940.   mov    si,OFFSET lineOffs
  1941.   mov    di,OFFSET bankNum
  1942.   xor    bx,bx                ; current line number = 0
  1943.  
  1944.   mov    ax,[bksize]            ; separate process if bksize=64 K
  1945.   cmp    ax,64
  1946.   je    @@noBnk
  1947.  
  1948.   mov    cl,10
  1949.   shl    ax,cl                ; AX = bank size in bytes
  1950.   dec    ax
  1951.   mov    [temp],ax            ; [temp] = banksize in bytes - 1
  1952.   mov    cl,10
  1953.   mov    ax,[bksize]            ; AX = bank size in K
  1954.       @@shlp:
  1955.   inc    cl
  1956.   shr    ax,1
  1957.   jnz    @@shlp                ; loop until AX = 0
  1958.  
  1959.   xor    ax,ax                ; AX = 0
  1960.   xor    dx,dx                ; DX = 0
  1961.       @@lp:
  1962.   push    ax                ; store AX
  1963.   shr    ax,cl
  1964.   add    dx,ax                ; update current bank number
  1965.   pop    ax                ; restore AX
  1966.   and    ax,[temp]            ; mask offset so it's < bank size
  1967.   mov    [cs:si],ax            ; save line offset
  1968.   add    si,2                ; update pointer
  1969.   mov    [cs:di],dx            ; save bank number
  1970.   add    di,2                ; update pointer
  1971.   add    ax,[scanline]            ; update offset
  1972.   inc    bx                ; update line number
  1973.   cmp    bx,SCREEN_DEEP
  1974.   jb    @@lp                ; loop until all lines done
  1975.   jmp    short    @@calcBankChange    ; calculate bank change table
  1976.  
  1977.       @@noBnk:
  1978.   xor    ax,ax                ; AX = 0
  1979.   xor    dx,dx                ; DX = 0
  1980.   mov    cx,[scanline]            ; CX = width of line in bytes
  1981.       @@nlp:
  1982.   mov    [cs:si],ax            ; store line offset
  1983.   add    si,2                ; update pointer
  1984.   mov    [cs:di],dx            ; store bank number
  1985.   add    di,2                ; update pointer
  1986.   add    ax,cx                ; add another line width
  1987.   adc    dx,0                ; increase bank number if overflow
  1988.   inc    bx                ; update current line number
  1989.   cmp    bx,SCREEN_DEEP
  1990.   jb    @@nlp                ; jump until all lines done
  1991.  
  1992.       @@calcBankChange:
  1993.   mov    di,OFFSET bankChanges        ; initialize pointer
  1994.   xor    ax,ax                ; AX = current line
  1995.       @@bankChangeLoop:
  1996.   mov    bx,ax                ; BX = current line
  1997.   shl    bx,1                ; to access a table of words
  1998.   mov    dx,[cs:bankNum+bx]        ; DX = bank at start of current line
  1999.   mov    bx,ax                ; BX = current line
  2000.   inc    bx                ; BX = next line
  2001.   shl    bx,1                ; to access a table of words
  2002.   mov    cx,[cs:bankNum+bx]        ; CX = bank at start of next line
  2003.   mov    si,[cs:lineOffs+bx]        ; SI = offset at start of next line
  2004.   or    si,si                ; is SI=0?
  2005.   jz    @@L1                ; yes, jump
  2006.   dec    cx                ; CX = bank at end of current line
  2007.       @@L1:
  2008.   cmp    cx,dx                ; are start and end banks the same?
  2009.   jne    @@newBank            ; bank changed, jump
  2010.   mov    [word ptr cs:di],1        ; store bank changed flag
  2011.   jmp    short    @@L2            ; jump
  2012.       @@newBank:
  2013.   mov    [word ptr cs:di],0        ; store bank same flag
  2014.       @@L2:
  2015.   add    di,2                ; update pointer
  2016.   inc    ax                ; update current line number
  2017.   cmp    ax,SCREEN_DEEP
  2018.   jb    @@bankChangeLoop        ; loop until all lines done
  2019.  
  2020.   pop    di si
  2021.   ret
  2022. ENDP
  2023.  
  2024.  
  2025.     ENDS
  2026.  
  2027. END
  2028.