home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / microcrn / issue_39.arc / PASCAL39.FIG < prev    next >
Text File  |  1987-12-01  |  21KB  |  639 lines

  1. ;           figure 1
  2. ;
  3. ;
  4. ;           Document scanner resident data capture software.
  5. ;           This software intercepts the real time clock interrupt
  6. ;           with a high speed data capture routine and also installs
  7. ;           a routine at interrupt vector 60H to provide scanning
  8. ;           functions to other programs.
  9. ;
  10. ;           Since this software incorporates itself into the real time
  11. ;           clock processing, it has the potential of interfering with
  12. ;           other resident software.  It is highly recommended that
  13. ;           the absolute minimum of other resident software be installed.
  14. ;
  15. ;           The software does NOT check for previous use of INT 60H.
  16. ;
  17. ;           Written for Eric Isaacson's A86 assembler.
  18. ;
  19. ;           CONST
  20. ;              joystick = 201H;
  21. ;              tickconst = 1024;
  22. ;
  23. joystick    equ     201h
  24. tickconst   equ     1024
  25. ;
  26. code        segment                     ; both code and data in same segment
  27. ;
  28.             jmp     init
  29. ;
  30. ;           VAR
  31. ;              count : CARDINAL;
  32. ;              counter : CARDINAL;
  33. ;              rasterPtr : POINTER TO raster;
  34. ;              scaning : BOOLEAN;
  35. ;              dosclk : ADDRESS;
  36. ;              tickcount : BYTE;
  37. ;              tickinc : BYTE;
  38. ;
  39. count       dw      ?
  40. counter     dw      ?
  41. ;
  42. raster_ofs  dw
  43. rasterPtr   dd      ?                   ; double word for far data
  44. scanning    db      0                   ; FALSE
  45. ;
  46. dosclk_ip   dw
  47. dosclk      dd      ?                   ; double word for far calls
  48. ;
  49. tickcount   dw      ?                   ; how many counter cycles?
  50. tickinc     dw      tickconst           ;  fast clock divisor default value
  51. ;
  52. ;           Restore/Set hardware clock chip
  53. ;
  54. restore_clock: xor  ax,ax               ; normal time constant = 0
  55. setclk:     push    ax
  56.             mov     al,36h              ; control register
  57.             out     43h,al
  58.             pop     ax
  59.             out     40h,al              ; count low byte
  60.             xchg    ah,al
  61.             out     40h,al              ; and high byte
  62.             ret
  63. ;
  64. ;           New clock routine, includes data capture from scanner
  65. ;
  66. fastclock:  push    ax                  ; interrupt routine, save registers
  67.             push    ds
  68.             push    es
  69.             push    cs                  ; make ds = cs
  70.             pop     ds
  71. ;
  72.             mov     al,scanning         ; are we scanning?
  73.             or      al,al
  74.             jz      notscanning         ; if z, no
  75. ;
  76.             push    bx                  ; scanning, save additional regs
  77.             push    cx
  78.             push    dx
  79. ;
  80.             mov     bx,raster_ofs       ; data address offset
  81.             mov     ax,raster_ofs+2     ;  and segment previously set
  82.             mov     es,ax               ;  when scan initiated.
  83. ;
  84.             mov     dx,joystick         ; input data address
  85.             in      al,dx               ;  get the data
  86.             mov     cl,4                ; then shift to low order nybble
  87.             ror     al,cl
  88.             and     al,0fh
  89. ;
  90.             push    si
  91.             mov     si,counter
  92. es          mov  b  [bx+si],al          ; store the data where M2 needs it
  93.             pop     si
  94.             inc     w counter           ; bump the count
  95.             mov     ax,count            ; done yet?
  96.             cmp     ax,counter
  97.             jnz     notdone             ; not done yet
  98. ;
  99.             xor     al,al               ; done, flip flag
  100.             mov     scanning,al
  101.             call    restore_clock       ; reset hardware
  102.             mov     tickcount,0         ; ready for next time
  103.             pop     dx
  104.             pop     cx
  105.             pop     bx
  106.             jmp     clkexit
  107. ;
  108. notdone:    pop     dx
  109.             pop     cx
  110.             pop     bx
  111. ;
  112.             mov     ax,tickcount
  113.             add     ax,tickinc          ; bump tick counter
  114.             mov     tickcount,ax
  115.             jnc     clkexit             ; if no overflow, not time for DOS
  116. ;
  117. notscanning:pushf                       ; simulate software interrupt
  118.             call    dosclk              ;  with pushf and far call
  119.             jmp     clkxit2             ; skip eoi to 8259 since dos does it
  120. ;
  121. clkexit:    mov     al,20h              ; end of interrupt command
  122.             out     20h,al              ; to 8259 interrupt controller
  123. clkxit2:    pop     es                  ; restore registers
  124.             pop     ds
  125.             pop     ax
  126.             iret
  127.  
  128. ;
  129. ;           Modula-2 activates the functions in this resident
  130. ;           software with an int 60H instruction.  The parameters
  131. ;           needed are passed in the registers AL, BX, CX, and DX.
  132. ;           AL = function #
  133. ;           BX = data (raster) offset
  134. ;           DX = data segment
  135. ;           CX = number of data points to capture or time constant
  136. ;
  137. ;           The functions currently supported are:
  138. ;           0 : report address of 'scanning' flag byte (DX:BX)
  139. ;           1 : restore original clock routine
  140. ;           2 : capture a scan line of data
  141. ;           3 : set fast clock speed 
  142. ;
  143. dispatch:                               ; M2 call has saved all regs
  144.             or      al,al               ;  report flag address?
  145.             jz      rprt_addr
  146. ;
  147.             cmp     al,1                ; restore clock to normal?
  148.             jz      killfast
  149. ;
  150.             cmp     al,2                ; get data
  151.             jz      capture
  152. ;
  153.             cmp     al,3                ; set fast clock divisor
  154.             jz      setfast
  155. ;
  156.             iret                        ; unrecognized function, ignore
  157. ;
  158. rprt_addr:  push    ds
  159.             push    cs                  ; data in code segment
  160.             pop     dx                  ;  segment address
  161.             mov     bx, offset scanning ; and offset
  162.             pop     ds                  ;  that's all it takes
  163.             iret
  164. ;
  165. setfast:    push    ds                  ; set fast clock divisor
  166.             push    cs
  167.             pop     ds
  168.             mov     tickinc,cx          ; simple isn't it?
  169.             pop     ds
  170.             iret
  171. ;
  172. killfast:   push    ds
  173.             push    cs
  174.             pop     ds
  175.             call    restore_clock       ; reset hardware
  176.             mov     dx,dosclk_ip        ; old offset value
  177.             mov     ds,dosclk_ip+2      ; and old segment
  178.             mov     ah,25h
  179.             mov     al,8
  180.             sti                         ; can we do an int if disabled?
  181.             int     21h
  182.             pop     ds
  183.             iret
  184. ;
  185. ;       Capture a line of data by setting scanning to TRUE
  186. ;       and activating the fast clock.
  187. ;
  188. capture:    push    ds
  189.             push    cs
  190.             pop     ds
  191.             mov     counter,0           ; data point counter
  192.             mov     count,cx            ;  # points to capture
  193.             mov     raster_ofs,bx       ; data destination offset
  194.             mov     raster_ofs+2,dx     ;  and segment
  195.             mov     scanning,0ffh       ; set scanning to TRUE
  196. ;
  197. ;
  198.             mov     ax,tickinc          ; set clock to fast rate
  199.             call    setclk
  200.             mov     tickcount,0         ; reset tick counter
  201.             pop     ds                  ; return to M2
  202.             iret
  203. ;
  204. ;
  205. ;           Install function dispatch routine 
  206. ;
  207. init:       mov     ah,25h              ; install interrupt function
  208.             mov     al,60H              ;  can only use 60 - 67
  209.             mov     dx, offset dispatch
  210.             push    cs
  211.             pop     ds
  212.             int     21h
  213. ;
  214. ;           Get and save old clock vector
  215. ;
  216.             push    es
  217.             mov     ah,35h              ; get vector function
  218.             mov     al,8h               ; clock vector #
  219.             int     21h
  220.             mov     dosclk_ip,bx        ; save the long address
  221.             mov     dosclk_ip+2,es
  222.             pop     es
  223. ;
  224. ;           Install new clock routine
  225. ;
  226.             push    ds
  227.             mov     ah,25h              ; install interrupt fxn
  228.             mov     al,8h
  229.             mov     dx, offset fastclock
  230.             push    cs
  231.             pop     ds
  232.             int     21h
  233.             pop     ds
  234. ;
  235. ;
  236. ;           exit to dos, remain resident
  237. ;
  238.             mov     dx,offset init
  239.             int     27h                 ; terminate but stay resident
  240. ;
  241. code        ends
  242.             end
  243.  
  244.  
  245.  
  246. **************************************************************************
  247. figure 2
  248. **************************************************************************
  249.  
  250.  
  251.  
  252. IMPLEMENTATION MODULE ScrnStuff;
  253.  
  254. FROM SYSTEM IMPORT BYTE, ADDRESS, GETREG, SETREG, AX, BX, CX, DX,
  255.                    SWI, ADR, CODE, OUTBYTE, DOSCALL;
  256. FROM Config IMPORT Xsize, Ysize, Interleave, Unused, ScrSegment;
  257.  
  258. (* The EXPORT list has changed since the previous version *)
  259. (* Depending on the compiler, you may need this EXPORT *)
  260. (*EXPORT QUALIFIED Raster, Screen, ArrayLen, Lines, ClrScr, GrabClock, RlsClock,
  261.                  FastClock, SlowClock, Scan, GraphMode, PixAddress, SetBit,
  262.                  ClrBit, InvertBit, TextMode, Buffer, SetClock;  *)
  263.  
  264. CONST
  265.    PUSHBP = 55H;     (* machine code for push BP *)
  266.    POPBP = 5DH;      (* likewise for pop BP *)
  267. VAR
  268.    GReg6845 : ARRAY [0..15] OF BYTE;
  269.    TReg6845 : ARRAY [0..15] OF BYTE;
  270.    Scanning : POINTER TO BOOLEAN;
  271.    A : ADDRESS;
  272.  
  273. PROCEDURE ClrScr (VAR S:Screen);
  274. (* Clear the graphics screen by filling its memory with zeroes *)
  275. (* Not horribly fast, but adequate *)
  276. VAR
  277.    I, J : CARDINAL;
  278. BEGIN
  279.    FOR J := 0 TO ArrayLen DO
  280.       S[0,J] := CHR(0);
  281.       END;
  282.    FOR J := 1 TO Interleave-1 DO
  283.       S[J] := S[0];
  284.       END;
  285. END ClrScr;
  286.  
  287.  
  288. PROCEDURE GrabClock (IntNum : CARDINAL; TickLen : CARDINAL; VAR OldTick : CARDINAL)
  289.                      :ADDRESS;
  290. (* On further reflection it appears that this procedure is not needed *)
  291. (* Its function is performed when the external resident routine is installed *)
  292. BEGIN
  293. END GrabClock;
  294.  
  295.  
  296.  
  297. PROCEDURE RlsClock (OldVector : ADDRESS; IntNum : CARDINAL; OldTick : CARDINAL);
  298. (* The functions of this procedure are implemented in SlowClock *)
  299. BEGIN
  300. END RlsClock;
  301.  
  302.  
  303. PROCEDURE FastClock;
  304. (* The functions of this procedure are performed automatically by Scan *)
  305. BEGIN
  306. END FastClock;
  307.  
  308. PROCEDURE SetClock(t:CARDINAL);
  309. (* Set a new divisor for the clock hardware.  The normal divisor is 65536
  310.    (0), which gives a 55mS clock tick.  Do NOT call this routine with a
  311.    parameter of zero or the real time clock interrupt processing will be
  312.    halted.  Use SlowClock below to restore the clock to its normal function.
  313.    It is also unrealistic to expect everything to get done if the divisor
  314.    is set to a value much smaller than about 512 but feel free to 
  315.    experiment *)
  316. BEGIN
  317.    SETREG(CX,t);     (* new time constant for timer chip *)
  318.    SETREG(AX,3);     (* external resident function 3 *)
  319.    CODE(PUSHBP);
  320.    SWI(60H);
  321.    CODE(POPBP);
  322. END SetClock;
  323.  
  324. PROCEDURE SlowClock;
  325. (* Restore the clock hardware and interrupt vector to their original state *)
  326. (* Do not execute this procedure until you are finished with all scans. *)
  327. (* If you plan to scan more than one image, execute this procedure only *)
  328. (* after the last one has been scanned.  The called routine restores the *)
  329. (* clock to normal operation but does NOT de-install the resident code. *)
  330. BEGIN
  331.    SETREG(AX,1); (* Function code for resident routine *)
  332.    CODE(PUSHBP); 
  333.    SWI(60H);     (* accessed through a software interrupt *)
  334.    CODE(POPBP);
  335. END SlowClock;
  336.  
  337. PROCEDURE StartPrinter;
  338. CONST
  339. (* Change these constants and add or delete DOSCALLs to match your printer *)
  340.    ESC = 33C;
  341.    L = 'L';
  342. VAR
  343.    I, J : CARDINAL;
  344. BEGIN
  345.    DOSCALL(5H,ESC);    (* output graphics prefix *)
  346.    DOSCALL(5H, L);
  347.    DOSCALL(5H, Xsize MOD 256); (* Low order byte of Xsize *)
  348.    DOSCALL(5H, Xsize DIV 256); (* high order of Xsize *)
  349.    FOR I := 1 TO Xsize DO
  350.       DOSCALL(5H,0);
  351.       END;
  352.  
  353. (* With my printer, the print head does not return to home position after
  354.    a line of print until until you start sending the next line of data.
  355.    This delay allows the print head to return to home, then begin it's
  356.    movement before data capture is begun.  You will have to experiment
  357.    to determine the proper loop values for your hardware.  You may want
  358.    to make these values variables, entered from the keyboard *)
  359.    FOR J := 0 TO 1 DO
  360.       FOR I := 0 TO 23000 DO END;  (* Short Delay to allow printhead to start *)
  361.       END;
  362. END StartPrinter;
  363.  
  364. PROCEDURE StepPrinter;
  365. CONST
  366. (* Change these constants and add or delete DOSCALLs to match your printer *)
  367. (* For the Star Micronics printer, this performs a 2/144" line feed *)
  368.    CR = 15C;
  369.    ESC = 33C;
  370.    J = 'J';
  371.    N = 2C;
  372.    SPACE = ' ';
  373. VAR
  374.    I : CARDINAL;
  375. BEGIN
  376.    DOSCALL(5H,SPACE);
  377.    DOSCALL(5H,CR);
  378.    DOSCALL(5H,ESC);
  379.    DOSCALL(5H,J);
  380.    DOSCALL(5H,N);
  381. END StepPrinter;    
  382.  
  383. PROCEDURE Scan (VAR R : Buffer);
  384. VAR
  385.    A : ADDRESS;
  386.    
  387. BEGIN
  388.    StartPrinter;
  389.    A := ADR(R); (* address of where Modula needs the data *)
  390.    SETREG(AX,2);
  391.    SETREG(BX,A.OFFSET);
  392.    SETREG(DX,A.SEGMENT);
  393.    SETREG(CX,Xsize);
  394.    CODE(PUSHBP);
  395.    SWI(60H);
  396.    CODE(POPBP);
  397.  
  398.    WHILE Scanning^ DO END;    (* This is a quick and dirty method.  More 
  399.                                  elegant would be to have the resident scan
  400.                                  software act as a M2 coroutine. *)
  401.    StepPrinter;
  402. END Scan;
  403.  
  404. (* I have tested GraphMode and TextMode on my video card in all three
  405.    modes, CGA, EGA and HGA.  (My card emulates all three)  I have NOT
  406.    tested the routines on the individual adapters *)
  407.  
  408. PROCEDURE GraphMode;
  409. (* For CGA and EGA, call BIOS procedures to set the high resolution  *)
  410. (* monochrome graphics mode.  For Hercules, directly re-program the  *)
  411. (* hardware.                                                         *)
  412. CONST
  413.    Idx6845 = 3b4h;   (* 6845 index register *)
  414.    Data6845 = 3b5h;  (* 6845 data register *)
  415.    VideoMode = 3b8h; (* mode control register *)
  416. VAR
  417.    I : CARDINAL;
  418. BEGIN
  419.    CASE Interleave OF
  420.       1 : (* EGA Mode *)
  421.          SETREG(AX,000FH);
  422.          SWI(10H);   |
  423.       2 : (* CGA Mode *)
  424.          SETREG(AX,0006H);
  425.          SWI(10H);   |
  426.       4 : (* HGA Mode *)
  427.          FOR I := 0 TO 15 DO
  428.             OUTBYTE(Idx6845,I);
  429.             OUTBYTE(Data6845,GReg6845[I]);
  430.             END;
  431.          OUTBYTE(VideoMode, 0eh);
  432.       ELSE;
  433.    END;
  434. END GraphMode;
  435.  
  436. PROCEDURE TextMode;
  437. (* Same comments as for GraphMode above *)
  438. CONST
  439.    Idx6845 = 3b4h;   (* 6854 index register *)
  440.    Data6845 = 3b5h;
  441.    VideoMode = 3b8h;
  442. VAR
  443.    I : CARDINAL;
  444. BEGIN
  445.    CASE Interleave OF
  446.       1 : (* EGA Mode *)
  447.          SETREG(AX,0002H);
  448.          SWI(10H);   |
  449.       2 : (* CGA Mode *)
  450.          SETREG(AX,0002H);
  451.          SWI(10H);   |
  452.       4 : (* HGA Mode *)
  453.          FOR I := 0 TO 15 DO
  454.             OUTBYTE(Idx6845,I);
  455.             OUTBYTE(Data6845,TReg6845[I]);
  456.             END;
  457.          OUTBYTE(VideoMode, 20h);
  458.          SETREG(AX,0002H);
  459.          SWI(10H);
  460.       ELSE;
  461.    END;           
  462. END TextMode;
  463.  
  464. PROCEDURE PixAddress (X:Xpos; Y:Ypos; VAR B:BitPos ): ADDRESS;
  465. (* From x and y pixel positions, calculate the physical address of the *)
  466. (* proper byte to modify.  Also returns the bit position within the    *)
  467. (* byte of the pixel.                                                  *)
  468. CONST
  469.    Xbytes = Xsize DIV 8;
  470. VAR
  471.    A : ADDRESS;
  472. BEGIN
  473.    A.SEGMENT := ScrSegment;
  474.    IF Interleave = 1 THEN
  475.       A.OFFSET := (Y * Xbytes) + (X DIV 8);
  476.    ELSE
  477.       A.OFFSET := (ArrayLen +1) * (Y MOD Interleave)
  478.                  +(Xbytes * (Y DIV Interleave))
  479.                  +(X DIV 8);
  480.       END;
  481.    B := 7 - (X MOD 8);
  482.    RETURN A;
  483. END PixAddress;
  484.  
  485. PROCEDURE SetBit (SrcByte:CHAR; BitNum:BitPos): CHAR;
  486. VAR
  487.    Temp : CARDINAL;
  488. BEGIN
  489.    Temp := ORD(SrcByte)*256+1;
  490.    SETREG(AX,Temp);
  491.    SETREG(CX,BitNum);
  492.    CODE(08H, 0C9H);     (* OR CL,CL  *)
  493.    CODE(74H, 02H);      (* JZ NOROT  *)
  494.    CODE(0D2H,0C0H);     (* ROL AL,CL *)
  495.    CODE(8,0C4H);        (* NOROT: OR AH,AL *)
  496.    GETREG(AX,Temp);
  497.    RETURN CHR(Temp DIV 256);
  498. END SetBit;
  499.  
  500.  
  501. PROCEDURE ClrBit (SrcByte:CHAR; BitNum:BitPos): CHAR;
  502. VAR
  503.    Temp : CARDINAL;
  504. BEGIN
  505.    Temp := ORD(SrcByte)*256+0feh;
  506.    SETREG(AX,Temp);
  507.    SETREG(CX,BitNum);
  508.    CODE(08H, 0C9H);     (* OR CL,CL  *)
  509.    CODE(74H, 02H);      (* JZ NOROT  *)
  510.    CODE(0D2H,0C0H);     (* ROL AL,CL *)
  511.    CODE(20H,0C4H);      (* NOROT: AND AH,AL *)
  512.    GETREG(AX,Temp);
  513.    RETURN CHR(Temp DIV 256);
  514. END ClrBit;
  515.  
  516. PROCEDURE InvertBit (SrcByte:CHAR; BitNum:BitPos): CHAR;
  517. VAR
  518.    Temp : CARDINAL;
  519. BEGIN
  520.    Temp := ORD(SrcByte)*256+1;
  521.    SETREG(AX,Temp);
  522.    SETREG(CX,BitNum);
  523.    CODE(08H, 0C9H);     (* OR CL,CL  *)
  524.    CODE(74H, 02H);      (* JZ NOROT  *)
  525.    CODE(0D2H,0C0H);     (* ROL AL,CL *)
  526.    CODE(30h,0C4H);      (* NOROT: XOR AH,AL *)
  527.    GETREG(AX,Temp);
  528.    RETURN CHR(Temp DIV 256);
  529. END InvertBit;
  530.  
  531. BEGIN
  532. (* Initialize the values for 6845 graphics mode *)
  533.    GReg6845[0] := BYTE(37h);
  534.    GReg6845[1] := BYTE(2dh);
  535.    GReg6845[2] := BYTE(30h);
  536.    GReg6845[3] := BYTE(05h);
  537.    GReg6845[4] := BYTE(60h);
  538.    GReg6845[5] := BYTE(00h);
  539.    GReg6845[6] := BYTE(57h);
  540.    GReg6845[7] := BYTE(57h);
  541.    GReg6845[8] := BYTE(02h);
  542.    GReg6845[9] := BYTE(03h);
  543.    GReg6845[10] := BYTE(00h);
  544.    GReg6845[11] := BYTE(00h);
  545.    GReg6845[12] := BYTE(00h);
  546.    GReg6845[13] := BYTE(00h);
  547.    GReg6845[14] := BYTE(00h);
  548.    GReg6845[15] := BYTE(00h);
  549.  
  550. (* Initialize values for 6845 text mode *)
  551.    TReg6845[0] := BYTE(61h);
  552.    TReg6845[1] := BYTE(50h);
  553.    TReg6845[2] := BYTE(52h);
  554.    TReg6845[3] := BYTE(0fh);
  555.    TReg6845[4] := BYTE(19h);
  556.    TReg6845[5] := BYTE(06h);
  557.    TReg6845[6] := BYTE(19h);
  558.    TReg6845[7] := BYTE(19h);
  559.    TReg6845[8] := BYTE(02h);
  560.    TReg6845[9] := BYTE(0dh);
  561.    TReg6845[10] := BYTE(0bh);
  562.    TReg6845[11] := BYTE(0ch);
  563.    TReg6845[12] := BYTE(00h);
  564.    TReg6845[13] := BYTE(00h);
  565.    TReg6845[14] := BYTE(00h);
  566.    TReg6845[15] := BYTE(00h);
  567.  
  568. (* Get address of scanning flag from external routine *)
  569.    SETREG(AX,0);  (* report address function *)
  570.    CODE(PUSHBP);
  571.    SWI(60H);
  572.    CODE(POPBP);
  573.    GETREG(DX,A.SEGMENT);
  574.    GETREG(BX,A.OFFSET);
  575.    Scanning := A;
  576. END ScrnStuff.
  577.  
  578.  
  579.  
  580. **************************************************************************
  581. figure 3
  582. **************************************************************************
  583.  
  584.  
  585.  
  586. MODULE TestScan;
  587. (* First run pixel capture software, all it does is scan and display.
  588.    My results with this show that:
  589.       1. In order to get reasonable resolution, the sensor will have to
  590.          be apertured.
  591.       2. The scanned image WILL need image processing.
  592.       3. The possibility to have lots of fun is good.
  593.                                                                   *)
  594.  
  595. FROM ScrnStuff IMPORT Screen, ClrScr, GraphMode, TextMode, Scan, 
  596.                       PixAddress, Buffer, SetBit, SetClock;
  597. FROM Terminal IMPORT KeyPressed;
  598. FROM Config IMPORT Xsize, Ysize;
  599.  
  600. CONST
  601.    TickSize = 1536;      (* real time clock chip divisor, this value gave
  602.                             reasonable results.  Subject to change. *)
  603. VAR
  604.    S [0b000h:0] : Screen; (* use appropriate constants for your adapter *)
  605.    I, J, K, L : CARDINAL;
  606.    B : Buffer;
  607.    A : POINTER TO CHAR;
  608.    BP : CARDINAL;          (* not used except as throwaway parameter *)
  609.    ch : CHAR;
  610.  
  611. BEGIN
  612.    ClrScr(S);              (* clear the screen *)
  613.    GraphMode;              (* put it in graphics mode *)
  614.    SetClock(TickSize);
  615.    FOR J := 0 TO Ysize-1 DO   (* for now, just try for same resolution as screen *)
  616.       Scan(B);                (* capture a line od data *)
  617.       FOR K := 0 TO Xsize-1 BY 8 DO   (* Xsize is bits, do a byte at a time *)
  618.          A := PixAddress(K,J,BP);     (* calculate byte address *)
  619.          ch := 0c;                    (* clear assembly variable *)
  620.          FOR L := 0 TO 7 DO           (* then do each bit in the byte *)
  621.             IF B[K+L] < 7C THEN       (* this inverts image, & monochrome mode *)
  622.                ch := SetBit(ch,7-L);
  623.                END;
  624.             END;
  625.          A^ := ch;             (* actual screen byte update here *)
  626.          END;
  627.       END;
  628.    WHILE NOT(KeyPressed()) DO END;    (* admire the picture for a bit *)
  629.    ClrScr(S);                         (* then do orderly exit *)
  630.    TextMode;                          (* should also SlowClock *)
  631. END TestScan.
  632.  
  633.    +(Xbytes * (Y DIV Interleave))
  634.                  +(X DIV 8);
  635.       END;
  636.    B := 7 - (X MOD 8);
  637.    RETURN A;
  638. END PixAd
  639.