home *** CD-ROM | disk | FTP | other *** search
/ The Hacker's Encyclopedia 1998 / hackers_encyclopedia.iso / etc / hardware / magstrp1.txt < prev    next >
Encoding:
Text File  |  2003-06-11  |  26.0 KB  |  503 lines

  1.  
  2.                          Magnetic stripe technology
  3.  
  4.  
  5. Figures and listings are at the end.
  6.  
  7.   Because of their widespread use, most magnetic cards adhere to well-defined
  8. standards that describe the physical and magnetic characteristics for a
  9. magnetic stripe on a plastic card. These standards outline specifications for a
  10. storage format and information interchange. This does not preclude other 
  11. encoding techniques or additional data tracks for specific applications, but in
  12. most cases it makes sense to adhere to at least the basic constraints. This
  13. gives you the choice of using any commercially available magnetic encoders for
  14. your application. The technique used for encoding magnetic cards is known as
  15. "Two-Frequency, Coherent Phase Recording". Allowing for the representation of
  16. single-channel, self-clocking serial data, this methodology is generally 
  17. referred to as F/2F. Self-clocking is achieved by combining data and clock bits
  18. together in a continuous, synchronous sequence. In this scheme, an intermediate
  19. flux transition signifies a one bit and the absence of an intermediate flux
  20. transition denotes a zero bit.
  21.   Three data tracks defined for use on standard magnetic cards each possess
  22. different bit densities and encoded character sets. The average bit density of
  23. track 1 is 210 bits per inch (bpi). Track 1 characters are made up of six data
  24. bits and an odd parity bit, encoded with the least-significant bit first and 
  25. the parity bit last, yielding a 64-character set. Taking the number of bits per
  26. inch and the number of bits per character, you can see track 1 has the capacity
  27. to hold 79 characters.
  28.   Track 2 has a bit density of 75 bpi, and track 3 uses 210 bpi. Both of these
  29. tracks allow the representation of a numeric-only character set. The characters
  30. for tracks 2 and 3 are encoded using a 4-bit binary-coded decimal subset with
  31. odd parity and, like track 1, are encoded with the least significant bit first
  32. and the parity bit last. The lower density of track 2 allows up to 40 numeric
  33. characters, where 107 numerics can be squeezed onto track 3. The actual number
  34. of usable characters will be fewer since you also have the Start Sentinel, End
  35. Sentinel, and LRC characters.
  36.   Though sometimes magnetic cards are moved past the read head mechanically,
  37. most applications rely on manually moving the card, either through a slotted
  38. reader or into an insertion-type reader. Typically the swipe rate is 5-20 inches
  39. per second (ips), with 50 ips being the fastest most card readers can handle. Of
  40. course, moving the card by hand will not only result in varying the absolute
  41. card velocity but, will also introduce incremental speed changes as the card
  42. accelerates and decelerates past the pickup. The F/2F scheme is very forgiving
  43. of such speed fluctuations. 
  44.   For all 3 tracks, the fundamental data format is similar and consists of the
  45. following elements: First, leading zero bits are encoded to indicate the 
  46. presence of an encoded magnetic card and provide synchronization pulses to the
  47. read head electronics and ultimately to the controller. Next, the Start Sentinel
  48. character is encoded which indicates the start of the actual data. The coded
  49. data follows. Next, the End Sentinel terminates the data portion of the card
  50. and followed by an LRC byte (used for error detection). The LRC is essentially
  51. a horizontal parity calculated by an exclusive-OR of all the data bits from the
  52. Start Sentinel to the End Sentinel (inclusive). Finally, trailing zeros follow
  53. the LRC and fill out the remainder of the card.
  54.                           ANATOMY OF A MAGNETIC CARD
  55.   The magnetic tracks have inherent characteristics based on details such as 
  56. code set and bit and character densities. International organizations such as
  57. Mastercard and VISA impose additional constraits for their participating members
  58. and standards exist for bank debit cards and ATM cards as well. These rules
  59. specify the exact content and format of each data field in aech track as well as
  60. the intended uses for the tracks. Naturally, for nonfinancial uses, it is not
  61. necessary to comply with these standards. For dedicated uses such as access 
  62. control, people tracking, and material tracking, adhering to the minimal 
  63. standards is adequate.
  64.   The most-often-used track is track 2, although it offers the lowest inform-
  65. ation density of the three. It contains all the information that is normally
  66. used for credit card transactions. When a customer name is required, track 1
  67. must be used since it is the only track that permits alphanumeric data. Track 3
  68. is specified for numeric-only data, but is unique. It is intended for change-
  69. able data and consequently may not only be read but may be rewritten by the
  70. transaction-handling equipment. A multitude of data fileds are contained in
  71. these various tracks. Figure 1 shows a brief run-down of what is generally 
  72. placed on tracks 1 and 2.
  73.                               REAL CARD READERS
  74. The recovery of magnetically encoded F/2F data can be accomplished directly
  75. with the use of just about any microcontroller. There are no particular
  76. difficulties in deciphering the raw F/2F data stream and many early magnetic
  77. read heads contained nothing more than signal amplifiers and line drivers.
  78. These are now artifacts  since all modern magnetic read heads contain integ-
  79. rated F/2F bit recovery circuitry and interface with the host controller in a
  80. standard fashion using three wires: CARD PRESENT, CLOCK, and DATA. The read
  81. heads usually rely on a single chip to perform the linear signal conditioning,
  82. sychronization, and recovery of individual bits from the data stream. The Mag-
  83. Tek 21006505 IC is representative of this type of data recovery circuit and its
  84. functionality is depicted in figure 2.
  85.   Linear conditioning consists of raising the level of the magnetic pickup's
  86. input signal, rejeting common-mode noise, conditioning and detecting the 
  87. signal, and finally providing a digital output for susequent processing. The
  88. enable/disable counters provide initialization for the recovery section. The
  89. recovery section locks onto the data rate and recovers the individual data bits
  90. from the data stream. The oscillator section provides the clocks for the recov-
  91. ery section and for the enable/disable timers. Card present goes low after 8 or
  92. 9 flux reversals are seen from the magnetic pickup and will return high about
  93. 50 ms after the last flux reversal. The strobe line signals that data is valid
  94. and is active low. The data pin indicates a one bit when it is low. Raw F/2F
  95. data can also be picked directly off the chip.
  96.   The data rate for a high-density trac scanned at 50 ips comes to 10500 bits
  97. per second (bps). This results in a transfer rate of 1500 characters per second
  98. for the 7-bit elements used on track 1, and 2100 characters per second using
  99. the 5-bit elements of track 3. I either case, this translates to a new bit 
  100. arriving at the controller just under every 100 us (microsecond). Even the most
  101. anemic controller should be able to keep up. With resonably good coding techni-
  102. ques, there should be no problem handling the entire data sampling phase on an
  103. interrupt-driven basis. The low-density (track 2) data flows at a more pedes-
  104. trian 3750 bps, yielding 750 5-bit characters per second, or a new bit every
  105. 266 us. Since most dual-track read heads provide track 1 and track 2 data, this
  106. indicates that handling both tracks simultaneously is feasible under interrupt
  107. control. Keep in mind that 50 ips is a rather fast scan rate; 20-30 ips is
  108. probably a more realistic limit.
  109.                              MAGNETIC BIT STORMS
  110.   When approaching a problem such as decoding magnetic cards, it pays to spend
  111. some time looking at the overall picture before starting to write the code. At
  112. first glance, it would seem that organizing the data into the prevailing element
  113. size during the sampling interval would make decoding easier. This could be
  114. easily done by ignoring all the leading zeros, with actual data storage comm-
  115. encing with the first one bit. Of course, this approach assumes you're getting
  116. good data. The fact that the data recovery is handled using well-proven hard-
  117. wae makes this assumption valid.
  118.   If all you need to do is decode the card in a forward direction, then going
  119. about things as I just described makes sense and reduces the coding effort to a
  120. trivial exercise. If you have to support reverse decoding then this is not the
  121. optimal solution. Having considered the tradeoffs of being able to decode a 
  122. magnetic card in both forward and reverse directions, I decided to structure the
  123. program to work equally well in either direction at the cost of a slight 
  124. increase in initial complexity. 
  125.   The first step in decoding is to acquire the serial bit stream. This can be 
  126. done using a dedicated sample loop or, with a little more work, using interrupt
  127. processing. Since the idea is the same regardless of the details, I decided to
  128. use a sample loop in my demonstration program (isting 1). The code simply
  129. records the incoming data stream and deposits the data in a sample buffer a byte
  130. at a time. Sampling begins when Card Present returns idle. Any incomplete byte
  131. that has been partially assembled at the time when sampling terminates is simply
  132. discarded. The abundance of leading and trailing zeros allows losing some bits
  133. at either end causing any problems. 
  134.   Once the sampling interval completes, control is transferred to the decoding
  135. algorithm. Presented in listing 2, the track-1 decode algorithm consists of 
  136. nothing more than some initialization and the essence of the decode logic.
  137. Limiting the gyrations contained in the main body of this routine not only makes
  138. the logic easy to follow, but permits the same code to handle the decoding in
  139. either a forward or reverse direction.
  140.   The initial entry point assumes a forward decode attempt and sets up the 
  141. necessary flags, pointers, and counters before jumping into the main initial-
  142. ization code. After initialization, the sample buffer is scanned for the first
  143. one bit, at which time a 7-bit element is assembled. If the parity is correct
  144. and the character code checks out to be a Start Sentinel, the code proceeds and
  145. starts pulling successive data elements from the sample buffer. If the data 
  146. element is not an End Sentinel, the character is translated to ASCII and stored
  147. in the decode buffer. Should an End Sentinel be detected, the program extracts
  148. the next character, which is assumed to be the LRC byte, and finally checks the
  149. calculated LRC for a value of zero.
  150.   The checks and balances included in the execution of this loop include things
  151. such as parity, a cumulative LRC, and checking to make sure I haven't run out of
  152. samples. If everything checks out, the program terminates and returns with the
  153. DPTR pointing to the decoded data buffer and the character count contained in
  154. ACC. Should a decode failure occur, a test is performed on the direction flag
  155. and if this is an attempt at a forward decode, the routine jumps to the reverse
  156. initialization entry point. The reverse entry is similar to the forward decode
  157. entry but sets up the sample pointer to the end of the sample buffer and sets 
  158. the direction flag to indicate a reverse operation.
  159.   The routines contained in the intermediate layer are shown in listing 3. The
  160. meaning and operation of these routines should be apparent. The key routine in
  161. this section is GET_BIT, which picks off the next bit from the sample buffer,
  162. essentially restoring the sequential nature of the initial magnetic bit stream.
  163. FIND_START is used to synchronize with the first one bit. GET_CHAR first checks
  164. to make sure it hasn't run out of samples, then assembles the next 7-bit data
  165. element while doing a parity test and LRC calculation. Any problems encountered
  166. here are sent back to the caller and are handled there. STORE_CHAR translates
  167. and deposits the data character into its respective location in the decoded-data
  168. buffer and increments the character counter.
  169.   Listing 4 shows the low-level code. These routines perform the most rudiment-
  170. ary functions and operate in accordance with the direction flag. INDEX_PTR 
  171. either increments or decrements the sample pointer, POSITION_BIT likewise does
  172. either a right or left shift and LOCATE_BIT returns the state of the least- or
  173. most- significant bit of the accumulator.
  174.                            GO AHEAD, TAKE A SWIPE
  175.   Let me touch on a few additional points that may not be immediately apparent
  176. before signing off. Storing the sampled data in a continuous stream makes the
  177. sample routine work equally well with the various bit configurations used for
  178. the different recording tracks. This would not be easily attained if you tried
  179. to generate a particular element format during sample time. Furthermore, if you
  180. look at the differences between the encoded character sets and the bit formats
  181. for the different tracks, you will find that they differ in only a few areas.
  182. With a few minor changes, such as the defined Start Sentinel, number of bits per
  183. element, and character translation method, the decode routine I've shown could
  184. easily be coerced to handle the decoding of any of the standard magnetic tracks.
  185.   As a matter of fact, by recoding and redefining the hard-coded constants as
  186. variables, these could be set up for the particular data track at execution
  187. time before invoking the decode function. Doing so would not only save program
  188. memory, but would also allow you to use a routine you were comfrtable with.  
  189.  
  190. *******************************************************************************
  191.                                                                FIGURE 1
  192. _____________________________________________________________________
  193. TRACK 1 |SS|FC|   PAN   |FS|   NAME   |FS|  ADDITIONAL DATA  |ES|LRC|
  194. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  195. Notes: Track 1 is limied to 79 characters including SS, ES, and LRC.
  196. Mastercard PAN is variable up to 16 characters maximum. VISA is 13 or 16
  197.  characters, including mod-10 check digit. 
  198. SS: Start sentinel (%)
  199. FC: Format code 
  200. FS: Field separator ({)
  201. ES: End sentinel (?)
  202. LRC: Longitudinal redundency check character
  203. PAN (primary account number): 19 digits max.
  204. NAME: 26 alphanumeric characters max.
  205. ADDITIONAL DATA: Expiration date 4  
  206.                  Restriction or type 3
  207.                  Offset or PVN 5
  208. ______________________________________________________________________
  209. TRACK 2 |SS|FC|      PAN      |FS|       ADDITIONAL DATA      |ES|LRC|
  210. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  211. SS: Start sentinel (;) (hex B)
  212. FS: Field separator (=) (hex D)
  213. ES: End sentinel (?) (hex F)
  214. LRC: Longitudinal redundency check character
  215. PAN (primary account number): 19 digits max.
  216. ADDITIONAL DATA: Expiration date 4  
  217.                  Restriction or type 3
  218.                  Offset or PVN 5
  219.  
  220. *****************************************************************************
  221.                                   FIGURE 2
  222. HEAD SIGNAL   __/~\__   __/~\__   __/~\__   __/~\__   __/~\__   __/~\_______
  223.                      `-`       `-`       `-`       `-`       `-`       
  224. ____ _______  __________                                                ____
  225. CARD PRESENT            |______________________________________________|
  226.  
  227. ____ ____     _____________________      ____           ____           _____
  228. READ DATA                          |____|    |_________|    |_________|
  229.  
  230. ____ ______   __________    __   __   __   __   __   __   __   __   __   __
  231. READ STROBE             |__|  |_|  |_|  |_|  |_|  |_|  |_|  |_|  |_|  |_|  |
  232.  
  233.                         |    0|   1|   0|   1|   1|   0|   1|   1|   0|   0|
  234.                         
  235.  
  236.                                                             ___ 
  237.                                HEAD 1-----X---X--------13 |MAG| 9--C2-R3
  238.                                            R1  C1          |TEK|        |
  239.                                 HEAD 2-----X---X--------12 |   | 10-----X--X
  240.                                                            |   |        |  |
  241.                                              X---X------11 |   |        |  R5
  242.                                     X-X      R2  C6        |   | 6------|--X
  243.                                     | |      X---X-------8 |   |        | 
  244. +5VDC --------------X--R7--X--------X-|-----------------14 |   | 7-----C3
  245.                     |      |+         |                    |   |       ____
  246.                     R6     C5         |                    |   | 16----DATA
  247.                     |      X----------|------------------5 |   |       ______
  248. ____ _______        |      |          X------------------2 |   | 15----STROBE
  249. CARD PRESENT -------X------|-----------------------------1 |   |
  250.                            |                  X----X-----3 |   |
  251.                            |                  C4   R4----4 |   |
  252. GND------------------------X------------------X            |___|
  253.  
  254. R=RESISTOR(Values weren't given)
  255. C=CAPACITOR(Values weren't given)
  256. X=CONNECTION BETWEEN WIRES
  257. MAG TEK is the Mag-Tek 21006505
  258.  
  259. *****************************************************************************
  260. LISTING 1-- Using several externally defined routines, a sample program to
  261.             read a stripe and store it in a buffer is very short.
  262.  
  263.             PUBLIC READ_MAG1
  264.             EXTERN MS1_BUF (XDATA)      ;sample buffer
  265.             EXTERN MS1_LIM (NUMBER)     ;sample limit
  266.             EXTERN MD1_BUF (XDATA)      ;decode buffer
  267.             EXTERN CP (BIT)             ;card present bit
  268.             EXTERN M1_CLK (BIT)         ;clock bit
  269.             EXTERN M1_DQ (BIT)          ;data bit  
  270.  
  271. M1_SS       EQU    5                    ;start sentinel
  272. M1_ES       EQU    1FH                  ;end sentinel
  273. ;
  274.             SEG    CODE
  275. ;Sampe and decode magnetic track 1
  276. ; output: ACC contains character count.
  277. ;         DPTR points to data buffer
  278. READ_MAG1   PROC             
  279.             CALL   MAG_SAMPLE
  280.             JZ     L?RM1
  281.             CALL   MAG1_DECODE
  282. L?RM1:      RET
  283.             ENDPROC
  284. ;General-purpose magnetic sampling routine
  285. ; output: ACC contains sample count
  286. MAG_SAMPLE  PROC
  287.             MOV    DPTR,#MS1_BUF
  288.             MOV    R1,#0                ;sample counter
  289. L?MS1:      MOV    R0,#8                ;bit counter
  290. L?MS2:      JB     CP,L?MS4
  291.             JB     M1_CLK,L?MS2
  292.             MOV    C,M1_DQ
  293. L?MS3:      JB     CP,L?MS4            
  294.             JNB    M1_CLK,L?MS3
  295.             CPL    C
  296.             RRC    A
  297.             DJNZ   R0,L?MS2
  298.             MOVX   @DPTR,A
  299.             INC    DPTR
  300.             INC    R1                   ;sample counter
  301.             CJNE   R1,#MS1_LIM,L?MS1
  302. L?MS4:      MOV    A,R1                 ;final sample count
  303.             RET
  304.             ENDPROC
  305.             
  306. *******************************************************************************
  307. LISTING 2-- Once the serial bit stream has been acquired, the decoding
  308.             algorithm takes over.
  309.  
  310. ;Bidirectional magnetic track 1 decode routine
  311. ;input: sample count in ACC, output: ACC contains character count
  312. ;       DPTR points to decoded data buffer
  313. ;Reg. usage for this routine (includes subroutines) as follows:
  314. ;R5: Direction flag, 0=forward
  315. ;R4: Cumulative LRC register
  316. ;R3: Decoded character counter
  317. ;R2: Nondecrementing sample count
  318. ;R1: Decrementing sample count
  319. ;R0: Bit syncronizing counter
  320. MAG1_DECODE PROC
  321.             ;1st pass, setup for forward decode attempt
  322.             MOV    R5,#0                ;indicate forward decode
  323.             MOV    DPTR,#MS1_BUF        ;point to start of buffer
  324.             MOV    R1,A                 ;sample counter
  325.             MOV    R2,A                ;sample count
  326.             JMP    L?M1D1                               
  327. L?M1D0:     ;2nd pass, setup for reverse decode attempt
  328.             MOV    R5,#1                ;indicate reverse decode
  329.             MOV    DPTR,#MS1_BUF
  330.             MOV    A,R2                 ;sample count
  331.             DEC    A
  332.             ADD    A,DPL
  333.             MOV    DPL,A
  334.             CLR    A
  335.             ADDC   A,DPH
  336.             MOV    DPH,A                ;point to end of buffer
  337.             MOV    R1,2                 ;sample counter
  338. L?M1D1:                                 ;decode initialization
  339.             MOV    R3,#0                ;character counter
  340.             MOV    R4,#0                ;inital LRC
  341.             MOV    R0,#0                ;bit syncronizer
  342.             CALL   FIND_START           ;main decode loop
  343.             JNC    L?M1D5               ;start bit error
  344.             CALL   GET_CHAR             ;Start Sentinel
  345.             JB     ACC.7,L?M1D5         ;format error
  346.             CJNE   A,#M1_SS,L?M1D5      ;start setinel error
  347. L?M1D2:                                 ;daa byte or End Sentinel              
  348.             CALL   GET_CHAR
  349.             JB     ACC.7,L?M1D5         ;format error
  350.             CJNE   A,#M1_ES,L?M1D3      ;end sentinel not found
  351.             JMP    L?M1D4
  352. L?M1D3:                 
  353.             CALL   STORE_CHAR           ;data character
  354.             JMP    L?M1D2
  355. L?M1D4:                                 ;LRC
  356.             CALL   GET_CHAR             ;get LRC                        
  357.             JB     ACC.7,L?M1D5         ;format error
  358.             MOV    A,R4             
  359.             JNZ    L?M1D5               ;LRC error
  360.             MOV    DPTR,#MD1_BUF        ;good return
  361.             MOV    A,R3                 ;final character
  362.             RET
  363. L?M1D5:     ;decode error, check if 1st pass
  364.             CJNE   R5,#1,L?M1D0         ;check direction
  365.             CLR    A                    ;bad return
  366.             RET
  367.             ENDPROC
  368.  
  369. *******************************************************************************
  370. LISTING 3-- The intermediate layer of software is one level removed from the
  371.             nitty-gritty details.
  372.  
  373. ;Get the next bit from the sample buffer
  374. ;output: C contains data bit
  375. GET_BIT     PROC             
  376.             CJNE   R0,#0,L?GB1          ;bit synchronizer
  377.             MOV    R0,#8
  378.             PUSH   ACC
  379.             MOVX   A,@DPTR
  380.             CALL   INDEX_PTR
  381.             MOV    B,A
  382.             POP    ACC
  383.             DEC    R1                   ;sample counter
  384. L?GB1:      XCH    A,B
  385.             CALL   POSITION_BIT
  386.             XCH    A,B
  387.             DEC    R0                   ;bit synchronizer
  388.             RET
  389.             ENDPROC
  390. ;
  391. ;Find the first '1' bit in the sample buffer
  392. ;output: C=1 if bit is found
  393. FIND_START  PROC
  394. L?FS1:
  395.             CJNE   R0,#0,L?FS2          ;bit synchronizer
  396.             MOV    R0,#8                
  397.             MOVX   A,@DPTR
  398.             CALL   INDEX_PTR
  399.             DJNZ   R1,L?FS2             ;sample counter
  400.             JMP    L?FS4                ;out of samples
  401. L?FS2:      CALL   LOCATE_BIT           ;test for a '1' bit
  402.             JC     L?FS3          
  403.             CALL   POSITION_BIT                                         
  404.             DEC    R0                   ;bit synchronizer
  405.             JMP    L?FS1
  406. L?FS3:                                  ;good return
  407.             MOV    B,A                  ;save copy in B
  408.             SETB   C
  409.             RET
  410. L?FS4:      CLR    C                    ;bad return
  411.             RET
  412.             ENDPROC
  413. ;
  414. ;Get the next 7 bit element from the sample buffer
  415. ;output: ACC contains data element
  416. ;        error flag is ACC.7
  417. GET_CHAR    PROC                                
  418.             MOV    A,R1                 ;sample counter
  419.             JZ     L?GC2                ;out of samples
  420.             MOV    R7,#7                ;bit counter
  421.             CLR    A
  422. L?GC1:      CALL   GET_BIT              ;next bit
  423.             RRC    A                    
  424.             DJNZ   R7,L?GC1
  425.             RR         A
  426.             JNB    P,L?GC2              ;parity error
  427.             ANL    A,#3FH               ;discard parity
  428.             PUSH   ACC
  429.             XRL    A,R4                 ;calculate LRC
  430.             MOV    R4,A
  431.             POP    ACC                  ;good return
  432.             RET
  433. L?GC2:      SETB   ACC.7                ;bad return
  434.             RET
  435.             ENDPROC
  436. ;Translate and store the data character
  437. ;input: ACC contains data character
  438. STORE_CHAR  PROC
  439.             PUSH   DPL
  440.             PUSH   DPH 
  441.             PUS   ACC
  442.             MOV    DPTR,#MD1_BUF
  443.             MOV    A,R3                 ;character counter
  444.             ADD    A,DPL
  445.             MOV    DPL,A
  446.             CLR    A
  447.             ADDC   A,DPH                ;generate displacement
  448.             MOV    DPH,A
  449.             POP    ACC
  450.             ADD    A,#' '               ;translate
  451.             MOVX   @DPTR,A              ;store
  452.             POP    DPH
  453.             POP    DPL
  454.             INC    R3                   ;character counter
  455.             RET
  456.             ENDPROC
  457.             
  458. *******************************************************************************
  459. LISTING 4-- The low-level routines get right down to the ground and take care
  460.             of the gory details.
  461.  
  462. ;Index the sample pointer either forward or backward
  463. INDEX_PTR          PROC
  464.             CJNE   R5,#0,L?IP1          ;check direction
  465.             INC    DPTR                 ;forward
  466.             RET
  467. L?IP1:      PUSH   ACC                  ;backward
  468.             DEC    DPL
  469.             MOV    A,DPL
  470.             CJNE   A,#-1,L?IP2
  471.             DEC    DPH
  472. L?IP2:      POP    ACC
  473.             RET
  474.             ENDPROC
  475.  
  476. ;Position bit is in ACC into C in either a right or left shift
  477. POSITION_BIT       PROC
  478.             CJNE   R5,#0,L?PB1          ;check direction
  479.             RRC    A                    ;forward
  480.             RET
  481. L?PB1:      RLC    A
  482.             RET
  483.             ENDPROC
  484.             
  485. ;Locate a 1 bit, either msb or lsb
  486. ;output: C=1 if bit is a one
  487. LOCATE_BIT         PROC
  488.             CJNE   R5,#0,L?LB1          ;check direction
  489.             MOV    C,ACC.0              ;forward
  490.             RET
  491. L?LB1:      MOV    C,ACC.7              ;backward
  492.             RET
  493.             ENDPROC
  494.             
  495. *******************************************************************************
  496. Contact:
  497.  Mag-Tek, Inc.
  498.  20725 S. Annalee Ave.
  499.  Carson, CA 90746
  500.  (213) 631-8602
  501.  fax: (213) 631-3956
  502. *******************************************************************************
  503.