home *** CD-ROM | disk | FTP | other *** search
- ;Copyright 1990 by John Wiley & Sons, Inc.
- ; All Rights Reserved.
- ;
- ;Generic Video Digitizer Routines in Turbo C - Computer Independent
- ;
- ; This version utilizes the 8253 timer/counter to time the sync pulses
- ; and should therefore be somewhat PC independent.
- ;
- ; written by Craig A. Lindley
- ; last update: 05/17/89
- ;
- ;NOTE: most code in this file is written as inline code for speed reasons.
- ; Any change to this structure might stop the digitizer from working.
- ; Any change in register usage might also cause it to stop working.
- ; Be careful changing the parameter passing linkage with C.
- ;
- _TEXT segment byte public 'CODE'
- DGROUP group _DATA,_BSS
- assume cs:_TEXT,ds:DGROUP,ss:DGROUP
- _TEXT ends
-
- _DATA segment word public 'DATA'
- ;
- Field1Found DW False ;True after field 1 of video located
- Field1Done DW False ;True after field 1 has been digitized
-
- PrtPortData DW 0 ;data output port
- PrtPortIn DW 0 ;data input port (5 bits)
- PrtPortCont DW 0 ;cont lines output port
- ImageReqPtr DW 0 ;ImageReq structure pointer passed from C
- DigitInit DW False ;True when digitizer has been initialized
- CompType DW 0 ;Holds type of PC configured
- ;
- ;these variables are only used when digitizing an Interlaced image. They
- ;contain the address of where the next column of digitized video will be
- ;stored. they are necessary because Interlaced data in a single frame must
- ;be stored in sequential locations in the picture buffer. because two passes
- ;through the picture buffer are necessary it is necessary to save when the
- ;next column of video should be stored when we get to digitizing it.
- ;
- PColSeg DW 0 ;segment for storage for this column of video
- PColOff DW 0 ;Offset in PColSeg for this column storage
- ;
- _DATA ends
-
- _BSS segment word public 'BSS'
- _BSS ends
- ;
- ;
- ;General Definitions
- ;
- True EQU 0FFH ;all ones is true
- False EQU 0 ;all zeros is false
- SegOff EQU (0FFFFH/10H)+1 ;paragraphs/segment
- ;
- ;PrtPortCont bit definitions
- ;
- Strobe EQU 1 ;used to latch pixel count data
- SyncReset EQU 2 ;reset for sync latch
- Go EQU 4 ;starts pixel counter
- HighLow EQU 8 ;selects highlow pixel count latch
- ;and highlow output data
- PrtPortContSafe EQU 0BH ;when written to PrtPortCont
- ;forces all bits (4) to zero. Go bit
- ;is special because it has inverter
- ;in the hardware.
- ;Bit combinations
- ;
- SetGo EQU PrtPortContSafe OR Go
- SetStrobe EQU PrtPortContSafe AND NOT Strobe
- SetHighLow EQU PrtPortContSafe AND NOT HighLow
- SetHighLowAndGo EQU PrtPortContSafe AND NOT HighLow OR Go
- SetSyncReset EQU PrtPortContSafe AND NOT SyncReset
- SetHighLowAndStrobe EQU PrtPortContSafe AND NOT HighLow AND NOT Strobe
- SetSyncResetAndGo EQU PrtPortContSafe AND NOT SyncReset OR Go
- ResetSyncAndEOC EQU PrtPortContSafe AND NOT SyncReset AND NOT HighLow
- ;
- ;PrtPortIn bit definitions
- ;
- SyncEOC EQU 8 ;bit monitored to detect sync
- ;and end of conversion (EOC).
- ;
- ;Video specific definitions
- ;
- HBlankingOffset EQU 47 ;additional count required for horiz
- ;blanking. 3.81 usec from rising edge
- ;of sync pulse at 12.38 MHz.
- VBlankingOffset EQU 16 ;sync pulses to consume before active
- ;video in field.
- SyncsField1 EQU 272 ;Number of sync pulses in field 1
- SyncsField2 EQU 271 ;ditto for field 2
- ;
- ;ImageReq definitions
- ;
- ;This structure is sent to this code from the high level C code to tell the
- ;digitizer what to digitize. This declaration does not allocate space, it
- ;just defines the offsets of the various fields. It must correspond exactly
- ;with the C structure ImageReq defined in the file gvideo.h for things to
- ;work properly.
- ;
- ImageReq struc
- ;
- ComputerType DW 0 ;used to adjust delays according to CPU speed
- PrtBase DW 0 ;printer port to use with digitizer
- HMode DW 0 ;low or high resolution mode selector 320/640
- ;pixels per line.
- VMode DW 0 ;non Interlace or Interlace mode. 200/480
- ;lines per frame of video.
- NumberOfPasses DW 0 ;determines number of passes across video
- Flags DD 0 ;misc flags
- PictBufOff DW 0 ;Offset/Segment of picture buffer
- PictBufSeg DW 0
- FirstLine DW 0 ;digitized portion of video selectors
- FirstPixel DW 0
- LastLine DW 0
- LastPixel DW 0
- ;
- ImageReq ends
- ;
- ;The following are the equates for the various PC types. The delay MACROs
- ;must be adjusted to the speed of the PC. These are used to decode the
- ;configured type of PC and adjust the delay MACROs accordingly. These are
- ;all possible entries into the ComputerType field of the ImageReq.
- ;
- PC477 EQU 0
- PCAT6 EQU 1
- PCAT8 EQU 2
- PS210 EQU 3
- PS216 EQU 4
- PS220 EQU 5
- PS225 EQU 6
- PS233 EQU 7
-
- LowRes EQU 0 ;320 pixels/line
- HighRes EQU 1 ;640 pixels/line
- NonInterlace EQU 0 ;acquire a single field of video
- Interlace EQU 1 ;acquire a frame of video
- ;
- ;
- ;8253 Timer Definitions
- ;Timer 2 is used for the timing of the sync pulses. This is a more accurate
- ;method than a software loop. All PCs have this timer/counter available
- ;it is normally used to produce the beep for the keyboard.
- ;
- ;The following are timer and I/O port addresses
- ;
- Timer2CountReg EQU 42H ;used to set counter values
- TimerCmdReg EQU 43H ;used to send mode cmds to timer chip
- Timer2GateReg EQU 61H ;gate reg 8255s address
- TermBitReg EQU 62H ;term bit reg 8255s address
- ;
- ;The following are bit assignments, masks and mode bytes
- ;
- TimerCount EQU 18 ;at 840 nsec period =~ 15 usec
- Timer2GateBit EQU 01H ;gate is bit 0 of 8255 port
- TermCntBitMask EQU 20H ;term bit is bit 5 of 8255 port
- Timer2Mode EQU 0B2H ;timer 2 select; load LSB then MSB
- ;counter mode = 1; binary counter
- ;
- _TEXT segment byte public 'CODE'
- ;
- ;Delay MACROs
- ;
- ;Short delay. This is used to allow the computers bus to recover between
- ;sequential accesses of the same I/O port.
- ;
- SDelay MACRO
- jmp short $+2
- jmp short $+2
- ENDM
- ;
- ;Strobe delay. This is used to make sure the software generated strobes are
- ;long enough for the hardware to see.
- ;
- StbDel MACRO
- push ax
- pop ax
- push ax
- pop ax
- push ax
- pop ax
- push ax
- pop ax
- ENDM
- ;
- ;Start of Assembly Language Procedures
- ;
- ;
- ; Procedure InitializeTimer2
- ;
- ; This procedure sets up the 8253 timer for use as a sync timer. Mode 1 of
- ; the counter is utilized. In this mode, when the gate signal transitions
- ; from a low to a high level, the counter is loaded with a previously set
- ; value and the counter starts counting down towards zero. When zero is
- ; reached, the terminal bit goes from a low to a high level. This procedure
- ; sets the mode for timer 2 and sets in the count for use by the Delay
- ; procedure.
- ;
- ; INPUT: none.
- ; OUTPUT: none but timer 2 is initialized and the count is loaded.
- ; USES: ax register.
- ; CALL: not callable from C.
- ;
- ;
- InitializeTimer2 proc near
- ;
- mov al,Timer2Mode ;load mode value
- out TimerCmdReg,al ;send it to the 8253
-
- SDelay
-
- mov ax,TimerCount ;get the timers count
- out Timer2CountReg,al ;set the LSB of the count
-
- SDelay
-
- mov al,ah ;get the MSB of count
- out Timer2CountReg,al ;set the MSB of the count
-
- ret
- ;
- InitializeTImer2 endp
- ;
- ; Procedure Delay
- ;
- ; This procedure uses timer 2 to delay for approximately 15 microseconds
- ; time it is called.
- ;
- ; INPUT: none.
- ; OUTPUT: none but timer 2 is used to produce a delay
- ; USES: ax register
- ; CALL: not callable from C.
- ;
- ;
- Delay proc near
- ;
- push dx ;save register
- in al,Timer2GateReg ;read the 8255 port
-
- SDelay
-
- and al,NOT Timer2GateBit ;set bit 0 low
- out Timer2GateReg,al ;set gate bit low at timer 2
-
- SDelay
-
- or al,Timer2GateBit ;set bit 0 high
- out Timer2GateReg,al ;set gate bit high at timer 2
-
- SDelay
-
- Del1: in al,TermBitReg ;read the terminal bit port
- and al,TermCntBitMask ;is the timer period over ?
- jnz Del2 ;if yes jmp
-
- SDelay
-
- jmp short Del1
- ;
- Del2: SDelay
- pop dx ;restore register
- ret
- ;
- Delay endp
- ;
- ;
- ; Procedure InitializeDigitizer
- ;
- ; This procedure initializes the digitizer hardware in preparation
- ; for usage. It is necessary to set the bits in the PrtPortCont latch
- ; to initialize digitizer. The HighLow line must be strobed to clear
- ; the SyncEOC line (because the EOC latch is then reset). If this is not
- ; done it is possible that the SyncEOC line will remain in a low state
- ; forever not allowing the Sync signal to leave the digitizer.
- ;
- ; INPUT: near pointer to the ImageReq data structure.
- ; OUTPUT: none but the digitizer hardware is initialized.
- ; USES: ax,bx,dx registers.
- ; CALL: callable from C.
- ; PROTOTYPE: InitializeDigitizer(sturct ImageReq *)
- ;
- Public _InitializeDigitizer
- ;
- _InitializeDigitizer proc near
- ;
- push bp ;prepare to retrieve the near pointer
- mov bp,sp ;to the ImageReq structure
- ;
- ;get and store the pointer from C which points at the ImageReq structure
- ;
- mov bx,[bp+4] ;bx pts at ImageReq
- mov ImageReqPtr,bx ;save in local var
- ;
- ;first thing to do is to retrieve the address of the printer port to use
- ;for the digitizer. we must know this for any communication with the
- ;digitizer. with the base address ,PrtBase, of the port known, we can easily
- ;calculate the other important port addresses.
- ;
- mov ax,[bx].PrtBase ;get port number to use
- mov PrtPortData,ax
- inc ax ;port+1= PrtPortIn
- mov PrtPortIn,ax
- inc ax ;port+2= PrtPortCont
- mov PrtPortCont,ax
- mov ax,[bx].ComputerType ;read the computer type
- mov CompType,ax ;store locally in ds
- ;
- ;now start the initialization of the digitizer hardware
- ;
- mov dx,PrtPortCont ;pt at control latch bits
- mov al,PrtPortContSafe ;initialize control bits
- out dx,al ;sent to the digitizer
- ;
- call Delay ;let things stabilize
- ;
- mov al,ResetSyncAndEOC ;set HighLow bit high
- out dx,al ;to clear EOC input to
-
- StbDel
- ;
- mov al,PrtPortContSafe ;initialize control bits
- out dx,al ;sent to the digitizer
-
- SDelay
-
- mov ax,0 ;set pixel count to 0
- call SetPixelCount ;send to hardware counters
-
- SDelay
-
- call InitializeTimer2 ;initialize the sync timer
- mov DigitInit,True ;indicate the digitizer has been
- ;initialized.
- pop bp ;restore bp to enable a return
- ret ;to C code.
- ;
- _InitializeDigitizer endp
- ;
- ;
- ; Procedure _SyncsPerField
- ;
- ; This procedure counts the number of sync pulses (of all variety) that
- ; occur in a single field of video. It must do its counting in 1/30 of
- ; a second field time. Field 1 should contain 272 syncs while field 2
- ; should contain 271.
- ;
- ; INPUT: none.
- ; OUTPUT: number of syncs in the monitored field returned in ax.
- ; USES: ax,cx,dx registers. bx perserved.
- ; CALL: callable from C.
- ; PROTOTYPE: unsigned short SyncsPerField ( void )
- ;
- Public _SyncsPerField
- ;
- _SyncsPerField proc near
- ;
- cli ;interrupts off
- call SyncsPerField ;count them
- sti ;ints back on
- ret
- ;
- _SyncsPerField endp
- ;
- ;
- ; Procedure SyncsPerField
- ;
- ; See discussion above
- ;
- ; INPUT: none.
- ; OUTPUT: number of syncs in the monitored field returned in ax.
- ; USES: ax,cx,dx registers. bx perserved.
- ; CALL: not callable from C.
- ;
- ;
- SyncsPerField proc near
- ;
- push bx ;save register
- mov bx,7 ;initialize count to include all
- ;vertical syncs will will miss
- mov dx,PrtPortCont ;pt at control register
- mov al,ResetSyncAndEOC ;hold sync latch and EOC reset
- out dx,al ;so only actual sync signal will
- ;be seen by the hardware.
- SDelay
- ;
- ;read SyncEOC line to see if it is low
- ;
- dec dx ;pt back at PrtPortIn
- spf1: in al,dx ;read data in
- and al,SyncEOC
- jz spf1 ;jump if SyncEOC is still low.
- ;
- ;check once again. A vertical sync interval would never be high two
- ;reads in a row.
- ;
- call Delay
- in al,dx
- and al,SyncEOC
- jz spf1 ;jump if long sync. Line still low.
-
- SDelay
- ;
- ;when we get here a short sync interval has been detected. Now find
- ;the first long sync (vertical sync) interval with which to start the
- ;sync count.
- ;
- call FindLongSync
- ;
- ;1st long sync pulse found. Advance to 1st short sync interval
- ;
- spf2: in al,dx
- and al,SyncEOC
- jz spf2 ;jump if SyncEOC is still low.
- ;
- ;check again.
- ;
- call Delay
- in al,dx
- and al,SyncEOC
- jz spf2 ;jump if long sync. Line still low.
-
- SDelay
- ;
- ;short sync interval found again. Count up all syncs until new long sync
- ;is found. This indicates end of field.
- ;
- spf3: in al,dx ;read input port
- and al,SyncEOC ;mask all but sync bit
- jnz spf3 ;loop until bit active (low)
-
- SDelay
- ;
- ;Sync latch has gone low. Reset it.
- ;
- inc dx ;now pt dx at PrtPortCont for output
- mov al,ResetSyncAndEOC ;set SyncReset high
- out dx,al ;do it
-
- StbDel
-
- mov al,PrtPortContSafe ;end SyncReset pulse
- out dx,al ;do it
-
- ;
- ;read again. Short syncs should be gone
- ;
- call Delay
- dec dx ;pt back at PrtPortIn
- in al,dx
- and al,SyncEOC
- jz spf4 ;we're done when long sync detected
- inc bx ;count the short sync
- jmp spf3 ;continue looking for long
- ;
- spf4: inc dx ;pt at control port
- mov al,ResetSyncAndEOC ;set Sync and EOC reset high
- out dx,al
-
- SDelay
-
- dec dx ;pt back at input
- ;
- mov ax,bx ;result in ax for return
- pop bx
- ret
- ;
- SyncsPerField endp
- ;
- ;
- ; Procedure FindLongSync
- ;
- ; Assumes it is called during active video line. That is, short syncs
- ; are being detected. In the routine, we set the sync reset line and the
- ; EOC reset line (HighLow) and leave them. We are only interested in the
- ; detection of long (vertical) sync periods so we don't need the assistance
- ; of the on board sync latch IC8a. Setting these lines guarantees that only
- ; the actual sync pulse will be seen on the SyncEOC line. This saves us
- ; the time in resetting the latch inside of the loop.
- ;
- ; INPUT: none
- ; OUTPUT: none but returns when long sync interval detected
- ; USES: ax, dx registers
- ; CALL: not callable from C.
- ; PROTOTYPE: none
- ;
- FindLongSync proc near
- ;
- mov dx,PrtPortCont ;pt at control port
- mov al,ResetSyncAndEOC ;set both sync and EOC reset bits
- out dx,al
-
- SDelay
-
- dec dx ;pt at input port
- fls1: in al,dx ;read input port
- and al,SyncEOC ;mask all but sync bit
- jnz fls1 ;loop until bit active (low)
- ;
- ;Sync latch has gone low. By the time we realize it and read port again
- ;all short syncs should be gone.
- ;
- call Delay ;wait 15 usec to be sure
- in al,dx ;read SyncEOC line again to be sure
- and al,SyncEOC
- jnz fls1 ;loop if line is now high => short
- ;
- ;when we get here long sync interval has been detected and we're done
- ;
- SDelay
- ret
- ;
- FindLongSync endp
- ;
- ;
- ; Procedure SetPixelCount
- ;
- ; This procedure sets the pixel counter latch on the digitizer board to
- ; the 16 bit value in the ax register. The digitizer hardware only uses
- ; 12 of the 16 bits at this time.
- ;
- ; INPUT: pixel count in ax
- ; OUTPUT: none
- ; USES: ax,cx,dx registers
- ; CALL: not callable from C.
- ;
- ;
- SetPixelCount proc near
- ;
- mov cx,ax ;save pixel count in cx reg
- ;
- mov dx,PrtPortData ;pt at output data port
- mov al,cl ;get LS byte of count
- out dx,al ;write LS byte of pixel count
-
- StbDel
-
- mov dx,PrtPortCont ;pt at control port to strobe counters
- mov al,SetStrobe ;start the stobe pulse
- out dx,al
-
- StbDel
-
- mov al,PrtPortContSafe ;strobe ended
- out dx,al
-
- SDelay
-
- mov dx,PrtPortData ;pt at data port again
- mov al,ch ;get MSB of original pixel count
- out dx,al ;send to pixel counter
-
- StbDel
-
- mov dx,PrtPortCont ;pt at control port to set HighLow high
- mov al,SetHighLow
- out dx,al
-
- StbDel
-
- mov al,SetHighLowAndStrobe ;strobe into counters
- out dx,al
-
- StbDel
-
- mov al,SetHighLow ;reset Strobe leave HighLow still high
- out dx,al
-
- StbDel
-
- mov al,SetSyncReset ;reset sync latch
- out dx,al
-
- StbDel
-
- mov al,PrtPortContSafe ;HighLow now low
- out dx,al
-
- SDelay
-
- ret
- ;
- SetPixelCount endp
- ;
- ;
- ; Procedure _SetPixelCount
- ;
- ; C callable version of above.
- ;
- ; INPUT: pixel count
- ; OUTPUT: none
- ; USES: ax,cx,dx registers
- ; CALL: callable from C.
- ; PROTOTYPE: void SetPixelCount ( unsigned short )
- ;
- ;
- Public _SetPixelCount
- ;
- _SetPixelCount proc near
- ;
- push bp
- mov bp,sp
- mov ax,[bp+4]
- call SetPixelCount
- pop bp
- ret
- ;
- _SetPixelCount endp
- ;
- ;
- ; Procedure _GetPicture
- ;
- ; This procedure digitizes a complete monochrome picture. It stores
- ; the data for the picture in a buffer whos address is passed to it from C.
- ; The function InitializeDigitizer must be called before this one so that
- ; the hardware and software are setup correctly. All instructions for how
- ; the digitizer should digitize a picture are contained in the ImageReq
- ; data structure.
- ;
- ; INPUT: BX is a near pointer to the ImageReq structure which contains all
- ; the information for the control of the digitizer.
- ; OUTPUT: returns True is picture data in buffer, False if error
- ; USES: all registers. saves bp,si and di registers as required by Turbo C
- ; CALL: callable from C.
- ; PROTOTYPE: GetPicture();
- ;
- PUBLIC _GetPicture
- ;
- _GetPicture proc near
- ;
- cmp DigitInit,True ;has digitizer been initialized ?
- je gp1 ;continue if so
- mov ax,False ;return a false indication to C
- ret
-
- gp1: push bp ;save for use by C
- push si ;save si,di in case register vars
- push di ;used in C code.
- ;
- mov bx,ImageReqPtr ;get ImageReq pointer into bx for use
- ;all struct references use bx as ptr
- mov es,[bx].PictBufSeg ;point es:bp at picture data buffer
- mov bp,[bx].PictBufOff
-
- mov PColSeg,es ;establish addr of 1st video column
- mov PColOff,bp
-
- mov Field1Done,False ;indicate field 1 not yet digitized
- mov Field1Found,False ;and has not been found yet
-
- mov si,[bx].FirstPixel ;get the first pixels (column) #
- cmp [bx].HMode,LowRes ;320 pixel line ?
- jne gp2 ;jump if not
- shl si,1 ;if 320 pixel line pixel # * 2
-
- gp2: add si,HBlankingOffset ;add in the blanking interval
- ;
- ;this is the top of the loop which digitizes a complete column of pixels
- ;from the video signal. CPU register si is the pixel count across a line
- ;whereas register di is the line count down the video image.
- ;
- gp3: mov Field1Done,False ;false until field 1 has been done
- mov di,[bx].FirstLine ;initialize line count to that
- ;specified in the ImageReq every
- ;time thru this loop
- mov es,PColSeg ;get address of this column
- mov bp,PColOff
- ;
- mov ax,si ;get pixel count
- call SetPixelCount ;load hardware pixel counters
- ;
- gp4: cmp Field1Found,True ;have we located desired field before?
- je gp7 ;if yes just find long sync interval
- ;
- ;when we get here we need to find the start of the first field at least once
- ;
- gp5: cli ;interrupts off from now on
- call SyncsPerField ;locate field 1
- cmp ax,SyncsField2 ;are we there ?
- jmp gp6 ;if start of field 1 then jump
- sti ;interrupts back on
- call Delay ;delay for short period
- call Delay ;delay for short period
- call Delay ;delay for short period
- jmp short gp5 ;repeat until we find it
- ;
- ;start of first field found
- ;
- gp6: mov Field1Found,True ;indicate it was found
- jmp short gp8
- ;
- ;when we get here we just need to find the start of every subsequent
- ;even or odd field
- ;
- gp7: cli ;interrupts off from here on
- mov di,[bx].FirstLine ;initialize line count
- call FindLongSync ;find vertical sync period
- ;
- ;when we get here we have located the start of a field. NOTE: both the
- ;Sync and the EOC reset lines are still held active because we are not
- ;afraid of missing a short sync. That is, we are still only interested in
- ;long sync intervals. In the code that follows, we will
- ;continuously read the input port until we see it go high indicating a
- ;short sync has been detected. At that point we are past all of the long
- ;sync pulses and can start counting out the vertical blanking interval.
- ;
- gp8: in al,dx
- and al,SyncEOC
- jz gp8 ;jump if SyncEOC is still low.
- ;
- ;check once more
- ;
- call Delay ;delay 15 usec to be sure its gone
- in al,dx
- and al,SyncEOC
- jz gp8 ;jump if long sync. Line still low.
-
- SDelay
- ;
- ;we've just found the 1st short sync interval. Its probably an equalization
- ;pulse. We must now consume all of the equalization and vertical blanking
- ;pulses to get to the start of the active video.
- ;
- inc dx ;pt at control port
- mov al,PrtPortContSafe ;end SyncReset pulse
- out dx,al ;so we can use latch to find all
- ;syncs no matter how small
- SDelay
-
- dec dx ;pt back at input port
- ;
- ;count off the number of lines in the field to ignor. If a full field/frame
- ;picture is being digitized then ignor only VBlankingOffset number. If a
- ;partial picture is being digitized, ignor VBlankingOffset + FirstLine number
- ;of lines.
- ;
- mov cx,VBlankingOffset ;consume this many on default picture
- ;
- ;check for field 2 digitization
- ;
- cmp Field1Done,True ;are we digitizing field 2 ?
- jne gp9 ;jmp if not
- inc cx ;if we are consume one more sync
- ;pulse to get rid of 1/2 line
- gp9: cmp [bx].FirstLine,0 ;req pict starts at line 0 ?
- je gp10 ;jmp if so
- add cx,[bx].FirstLine ;else add in additional lines to ignor
-
- gp10: in al,dx ;read input port
- and al,SyncEOC ;mask all but sync bit
- jnz gp10 ;loop until sync seen
-
- SDelay
- ;
- ;Sync latch has gone low. Reset it.
- ;
- inc dx ;now pt dx at PrtPortCont for output
- mov al,ResetSyncAndEOC ;set SyncReset high
- out dx,al ;do it
-
- StbDel
-
- mov al,PrtPortContSafe ;end SyncReset pulse
- out dx,al ;do it
-
- SDelay
- ;
- ;Sync latch is now reset. SyncEOC line should go inactive (high) shortly
- ;because we are expecting only short sync pulses.
- ;
- dec dx ;pt at PrtPortIn
- dec cx ;one less sync to consume
- jnz gp10 ;still more ?
- ;
- ;we have now consumed all the vertical blanking sync pulses. Set Go so
- ;pixel counters will be triggered on rising edge of sync pulse from camera.
- ;
- inc dx ;pt at control port
- mov al,SetGo ;set the go bit so counters will be
- out dx,al ;triggered by rising edge of sync
-
- SDelay
-
- dec dx ;pt at input port
- ;
- ;we are now at the start of the active video line. We must now process each
- ;digitization in less than one line time of 63.5 usec.
- ;
- gp11: in al,dx ;look for falling edge of sync pulse
- and al,SyncEOC
- jnz gp11
-
- SDelay
- ;
- ;line started with falling edge of SyncEOC
- ;
- inc dx ;pt at Cont port
- mov al,SetSyncResetAndGo ;reset sync latch and keep Go
- ;line high to start pixel count
- out dx,al ;on rising edge of every sync
-
- StbDel
-
- mov al,SetGo ;end SyncReset but leave Go active
- out dx,al ;do it
-
- SDelay
- ;
- ;Sync latch is now reset and pixel counters should be running.
- ;SyncEOC line should go active (low) shortly when the converted data becomes
- ;available.
- ;
- dec dx ;pt at PrtPortIn
- gp12: in al,dx ;read input port
- mov cl,al ;copy data to cl reg
- and al,SyncEOC ;mask all but EOC bit
- jnz gp12 ;loop until data ready
-
- SDelay
- ;
- ;we now have four bits of the video digital data in cl register as follows:
- ; 7 6 5 4 3 2 1 0
- ; D D D D EOC X X X
- ;after we shift it right four places it looks like
- ; 7 6 5 4 3 2 1 0
- ; 0 0 0 0 D D D D
- ;
- shr cl,1
- shr cl,1
- shr cl,1
- shr cl,1
- ;
- ;prepare to retrieve the MS nibble of data from the digitizer
- ;
- inc dx ;pt at Cont port
- mov al,SetHighLowAndGo ;set High/Low high to get 2 MSBs.
- out dx,al ;this also resets EOC
-
- SDelay
-
- dec dx
-
- in al,dx ;get the two MSBs
- and al,30H ;mask all but bits of interest
- or cl,al ;combine to get 6 total bits/pixel
- ;
- mov es:[bp],cl ;store all 6 bits of data
- ;
- gp13: inc dx ;pt at Cont port
- mov al,SetGo ;HighLow low again leave Go active
- out dx,al ;do it
- dec dx
- ;
- ;check to see if pointer for data storage (bp register) will leave a 64K
- ;segment. If so the segment register must be adjusted by SEGOFF so
- ;offset 0 into the segment points at the next available byte of storage.
- ;NOTE: when digitizing an interlaced picture, where it is necessary to
- ;skip every other location in the picture buffer, the check for segment end
- ;must be slightly different. To accomodate this, the code that follows is
- ;executed conditionally depending upon interlaced digitization or not.
- ;
- cmp [bx].VMode,Interlace ;are we in interlace mode ?
- je gp15 ;jmp if so
- ;
- ;when we get here we are in non Interlace mode
- ;
- cmp bp,0FFFFH ;at end of seg ?
- jne gp14 ;jump if not
- mov ax,es ;get seg reg value
- add ax,SEGOFF ;add offset
- mov es,ax ;store it back
- ;segment offset will inc to 0000
- ;
- ;check to see if we are done with a column of pixels
- ;
- gp14: inc bp ;bump the data pointer
- inc di ;inc the line count
- cmp di,[bx].LastLine ;bottom of picture ?
- jb gp11
- ;
- mov PColSeg,es ;save ptr to next storage location
- mov PColOff,bp
- ;
- jmp gp19 ;jmp to common exit code
- ;
- ;when we get here we are in Interlace mode
- ;
- gp15: cmp bp,0FFFEH ;at end of seg ?
- jb gp16 ;jump if not
- mov ax,es ;get seg reg value
- add ax,SEGOFF ;add offset
- mov es,ax ;store it back
- ;seg offset will inc to 0000
- ;
- gp16: inc bp ;bump the data pointer
- inc bp ;and again to leave room for data from
- ;other field
- inc di ;inc the line count
- mov ax,[bx].LastLine ;get last line of Interlaced frame
- shr ax,1 ;divide by two for last line per field
- cmp di,ax ;bottom of field ?
- jae gp17
- jmp gp11
- ;
- ;we are now done with one field of video for the Interlaced image. Go
- ;back and digitize the other field.
- ;
- gp17: cmp Field1Done,True ;done with this column in both fields ?
- je gp18 ;jmp if so
- ;
- ;when we get here we know we need to go back and do the other field
- ;
- mov Field1Done,True ;set flag to say we're finished on
- ;next pass
- mov es,PColSeg ;reload this columns pointer
- mov bp,PColOff
- ;
- inc bp ;bump one to miss data from other
- ;field
- jmp gp7 ;get next fields data
- ;
- gp18: mov PColSeg,es ;save addr of where next columns
- dec bp
- mov PColOff,bp ;data should start
- ;
- ;we are now done with a column of the video display. Advance to next pixel
- ;or next column. This is true for both Interlace and non Interlace
- ;digitizations.
- ;
- gp19: inc dx ;pt at Cont port
- mov al,PrtPortContSafe ;reset all control lines
- out dx,al ;just to be safe
- SDelay
- sti ;interrupts back on because timing
- ;between frames is not that critical
-
- cmp [bx].HMode,LowRes ;a 320 pixel picture ?
- jne gp20 ;jmp if not
- ;
- ;when we get here we know we are digitizing a 320 pixel line picture. we
- ;must increment the pixel count twice (two 640 pixels = one 320 pixel)
- ;and check to see if we are done digitizing a picture. this is complicated
- ;by the fact that the pixel counts are actually twice as big so we must
- ;compare with twice the LastPixel value.
- ;
- inc si
- inc si
- mov ax,[bx].LastPixel ;get the final pixel count
- shl ax,1 ;* 2 for comparison
- add ax,HBlankingOffset ;added in blanking interval
- cmp si,ax ;is the 320 pixel pict done ?
- jae gp21 ;jmp if so
- jmp gp3 ;if not do next pixel column
- ;
- ;when we get here we know we are digitizing a 640 pixel line picture. This
- ;is a much easier case than the 320 pixel picture shown above.
- ;
- gp20: inc si ;bump pixel count once for high res
- mov ax,[bx].LastPixel ;get last pixel #
- add ax,HBlankingOffset ;added in blanking interval
- cmp si,ax ;is the 640 pixel pict done ?
- jae gp21 ;if so jump
- jmp gp3 ;if not do next pixel column
- ;
- ;a complete picture is now digitized. Prepare to return to C.
- ;
- gp21: pop di
- pop si
- pop bp
- mov ax,True ;indicate no error to C
- ret
- ;
- _GetPicture endp
- ;
- ;End of video routines
- ;
- _TEXT ends
- end