home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / program / books / 68k_book / arp_src / prg_3ap.s < prev    next >
Text File  |  1985-11-20  |  13KB  |  253 lines

  1.  ; Program Name: PRG_3CP.S
  2.  
  3.  ; Assembly Instructions:
  4.  
  5.  ;    Assemble in PC-relative mode and save with a TOS extension.
  6.  
  7.  ; Execution Instructions:
  8.  
  9.  ;    Execute from the desktop.  Terminate execution by pressing the Return
  10.  ; key.
  11.  
  12.  ; Function:
  13.  
  14.  ;    Verifies that the results from two binary to ASCII decimal conversion
  15.  ; algorithms are identical.  The first conversion algorithm is called the
  16.  ; "repeated division" method; the number to be converted is repeatedly
  17.  ; divided by 10.  The second algorithm is called the "repeated subtraction"
  18.  ; method; powers of ten are repeatedly subtracted from the number to be
  19.  ; converted.
  20.  
  21.  ; Notes: 1 - "clr.w  Dn" is one of the fastest ways to clear only the
  22.  ;            lower word of a data register.
  23.  ;        2 - The stack used in the program is small enough to permit easy
  24.  ;            access to its contents via the AssemPro debugger.
  25.  ;        3 - In the "repeated division" algorithm, a null character must
  26.  ;            be stored in the array "reversed" for proper operation of
  27.  ;            the "reversed_to_decimal" loop, when the program is
  28.  ;            executed from AssemPro.  This is true because AssemPro will
  29.  ;            not necessarily clear the array to zeroes.
  30.  
  31.  ;            When the program is executed from the desktop, however, the
  32.  ;            operating system will clear the array.  Therefore, if the
  33.  ;            program were intended for use such as it is, the instruction
  34.  ;            which stores the null at the end of the array "reversed"
  35.  ;            could be eliminated.
  36.  
  37.  ;            Note that this is only one of the many types of adjustments
  38.  ;            which must be made when executing programs from debuggers.
  39.  
  40. calculate_program_size:
  41.  lea        program_end, a0     ; Put "end of program" address in A0.
  42.  movea.l    4(a7), a1           ; Put "basepage" address in A1.
  43.  suba.l     a1, a0              ; Subtract basepage address from A0.
  44.  lea        stack, a7           ; Point A7 to this program's stack.
  45.  
  46. return_memory:                  ; Return unused memory to operating system.
  47.  pea        (a0)                ; Store total program length in stack.
  48.  pea        (a1)                ; Store basepage address in stack.
  49.  move.l     #$4A0000, -(sp)     ; Function = m_shrink = GEMDOS $4A.
  50.  
  51.  ; NOTE: The above instruction is a combination of two most often seen
  52.  ;       in references:
  53.  
  54.  ;       move.w     d0, -(sp)   ; Dummy value, can be anything.
  55.  ;       move.w     #$4a, -(sp) ; Function = m_shrink = GEMDOS $4A.
  56.  
  57.  trap       #1                  ; GEMDOS call.
  58.  lea        $C(sp), sp          ; Reset stack pointer to top of stack.
  59.  
  60. mainline:                       ; Marks the beginning of program proper.
  61.  lea        heading, a0         ; Print heading for program's output.
  62.  bsr        print_string
  63.                             
  64. repeated_division_method_1:
  65.  lea        message_1, a0      
  66.  bsr        print_string       
  67.  move.l     #2147483647, d1     ; Number to be converted to ASCII decimal.
  68.  bsr        bin_to_dec_1        ; Routine expects number to be in D1.
  69.  lea        decimal, a0         ; to print_string alters the stack by pushing
  70.  bsr        print_string        ; the return address onto the stack.
  71.  
  72.  ; NOTE: Remember, although the number we store in D1 appears to our eyes
  73.  ;       to be a very familiar decimal number, the computer does not see
  74.  ;       it that way.  It is the assembler that lets us see things that
  75.  ;       are palatable to us while we are programming, and which, during
  76.  ;       assembly, converts that which we like to something the computer
  77.  ;       likes.  And the computer likes binary.
  78.  
  79. repeated_subtraction_1:
  80.  move.l     #2147483647, d1     ; Number to be converted to ASCII decimal.
  81.  bsr        bin_to_dec_2        ; Routine expects number to be in D1.
  82.  lea        message_2, a0
  83.  bsr        print_string 
  84.  lea        decimal, a0  
  85.  bsr.s      print_string 
  86.  bsr        print_newline
  87.  
  88. repeated_division_method_2:
  89.  move.l     #-7483647, d1       ; Binary number to be converted to decimal.
  90.  bsr        bin_to_dec_1        ; Routine expects number to be in D1.
  91.  lea        message_1, a0       ; Address of string cannot be pushed onto
  92.  bsr.s      print_string        ; stack here because the subroutine call
  93.  lea        decimal, a0         ; to print_string alters the stack by pushing
  94.  bsr.s      print_string        ; the return address onto the stack.
  95.  
  96. repeated_subtraction_method_2:
  97.  move.l     #-7483647, d1       ; Number to be converted to ASCII decimal.
  98.  bsr        bin_to_dec_2        ; Routine expects number to be in D1.
  99.  lea        message_2, a0       ; Address of string cannot be pushed onto
  100.  bsr.s      print_string        ; stack here because the subroutine call
  101.  lea        decimal, a0         ; to print_string alters the stack by pushing
  102.  bsr.s      print_string        ; the return address onto the stack.
  103.  bsr.s      print_newline
  104.  
  105. repeated_division_method_3:
  106.  move.l     #0, d1              ; Number to be converted to ASCII decimal.
  107.  bsr.s      bin_to_dec_1        ; Routine expects number to be in D1.
  108.  lea        message_1, a0       ; Address of string cannot be pushed onto
  109.  bsr.s      print_string        ; stack here because the subroutine call
  110.  lea        decimal, a0         ; to print_string alters the stack by pushing
  111.  bsr.s      print_string        ; the return address onto the stack.
  112.  
  113. repeated_subtraction_method_3:
  114.  move.l     #0, d1              ; Number to be converted to ASCII decimal.
  115.  bsr        bin_to_dec_2        ; Routine expects number to be in D1.
  116.  lea        message_2, a0       ; Address of string cannot be pushed onto
  117.  bsr.s      print_string        ; stack here because the subroutine call
  118.  lea        decimal, a0         ; to print_string alters the stack by pushing
  119.  bsr.s      print_string        ; the return address onto the stack.
  120.  bsr.s      print_newline
  121.  
  122. wait_for_keypress:
  123.  move.w     #8, -(sp)           ; Function = c_necin = GEMDOS $8.
  124.  trap       #1                  ; GEMDOS call.
  125.  addq.l     #2, sp              ; Reposition stack pointer at top of stack.
  126.  
  127. terminate:
  128.  move.w     #0, -(sp)           ; Function = p_term_old = GEMDOS $0.
  129.  trap       #1                  ; GEMDOS call.
  130.  
  131.  ;
  132.  ; SUBROUTINES
  133.  ;
  134.  
  135. print_string:                   ; Expects address of string to be in A0.
  136.  move.l     a0, -(sp)           ; Push address of string onto stack.
  137.  move.w     #9, -(sp)           ; Function = c_conws = GEMDOS $9.
  138.  trap       #1                  ; GEMDOS call
  139.  addq.l     #6, sp              ; Reposition stack pointer.
  140.  rts
  141.  
  142. print_newline:                  ; Prints a carriage return and linefeed.
  143.  pea        newline             ; Push address of string onto stack.
  144.  move.w     #9, -(sp)           ; Function = c_conws = GEMDOS $9.
  145.  trap       #1                  ; GEMDOS call
  146.  addq.l     #6, sp
  147.  rts
  148.  
  149.  ; The binary to ASCII decimal conversion subroutine uses an algorithm
  150.  ; based on the "repeated division" algorithm discussed in chapter 9 of the
  151.  ; Ford & Topp book; however, the algorithm used here is not limited to a
  152.  ; 16-bit binary number.  There is a similar algorithm in the Atari section
  153.  ; of appendix B in the Skinner book. The divisor is decimal 10.
  154.  
  155. bin_to_dec_1:                   ; Converts 32-bit binary number in D1 to
  156.                                 ; ASCII decimal.
  157.  lea        decimal, a0         ; Point to beginning of array "decimal".
  158.  lea        reversed + 10, a1   ; Point to end of array "reversed".
  159.  move.b     #0, (a1)            ; Put a null at the end of the array.
  160. _get_sign:
  161.  tst.l      d1                  ; Is binary number positive, negative or zero?
  162.  beq.s      _zero_passed        ; Branch if number is 0.
  163.  bpl.s      _positive           ; Branch if positive.
  164.  move.b     #$2D, (a0)+         ; Store a minus sign in array decimal.
  165.  neg.l      d1                  ; Change number from negative to positive.
  166.  bra.s      division_loop
  167. _positive:                      ; Branch to here when number is positive.
  168.  move.b     #$20, (a0)+         ; Store a space in array decimal.
  169. division_loop:                 
  170.  move.w     d1, d2              ; Store lower word in temp register D2.
  171.  clr.w      d1                  ; Clear lower word.  
  172.  swap       d1                  ; Move higher word to lower word.
  173.  divu       #10, d1             ; Divide full 32 bits by ten.
  174.  move.w     d1, d3              ; Store quotient in temp register D3.
  175.  move.w     d2, d1              ; Combine lower word with remainder.
  176.  divu       #10, d1             ; Divide full 32 bits by ten.
  177.  swap       d1                  ; Swap quotient and remainder words.
  178. _convert_to_ascii:              ; Convert digit to ASCII and store it.
  179.  addi.b     #$30, d1            ; Convert digit to ASCII.
  180.  move.b     d1, -(a1)           ; Store the digit in array "reversed".
  181.  move.w     d3, d1              ; Bring in higher word quotient. 
  182.  swap       d1                  ; Swap high and low word quotients.
  183.  tst.l      d1                  ; Is content of D1 zero yet?
  184.  bne.s      division_loop       ; Continue until content of D1 is zero.
  185. reversed_to_decimal:            ; Transfer contents of "reversed" to "decimal".
  186.  move.b     (a1)+, (a0)+        ; Loop until the null is transfered.
  187.  bne.s      reversed_to_decimal
  188.  rts
  189. _zero_passed:
  190.  move.b     #$20, (a0)+         ; Store a space in array "decimal".
  191.  move.b     #$30, (a0)+         ; Store the zero in array "decimal".
  192.  move.b     #0, (a0)            ; Terminate the decimal string with a null.
  193.  rts
  194.  
  195.  ; Conversion from binary to ASCII decimal using repeated subtraction.
  196.  ; See documentation in program PRG_3AP.S
  197.  
  198. bin_to_dec:                  
  199.  lea        decimal, a0         ; Put address of array "decimal" in A0.
  200.  lea        subtrahend, a1      ; Put address of subtrahend table in A1.
  201.  move.l     (a1)+, d0           ; Put first subtrahend in D0.
  202.  moveq      #0, d2              ; Initialize subtractions counter to zero.
  203. get_sign:
  204.  tst.l      d1                  ; Is binary number positive, negative or zero?
  205.  beq.s      zero_passed         ; Branch if number is 0.
  206.  bpl.s      positive            ; Branch if positive.
  207.  move.b     #$2D, (a0)+         ; Store a minus sign in array "decimal".
  208.  neg.l      d1                  ; Change binary number from neg to pos.
  209.  bra.s      discard_leading_zeroes
  210. positive:                       ; Branch to here when number is positive.
  211.  move.b     #$20, (a0)+         ; Store a space in array decimal.
  212. discard_leading_zeroes:         ; Subtract subtrahend from minuend.
  213.  sub.l      d0, d1              ; Loop till difference is positive,
  214.  bpl.s      subtract            ; indicating that digit is not zero.
  215.  add.l      d0, d1              ; Restore minuend.
  216.  move.l     (a1)+, d0           ; Get next subtrahend.
  217.  bra.s      discard_leading_zeroes
  218. subtract:
  219.  addq.b     #1, d2              ; Increment subtractions counter.
  220.  sub.l      d0, d1              ; Subtract subtrahend from D1.
  221.  bpl.s      subtract            ; Loop until D1 becomes negative.
  222. convert_to_ascii:
  223.  addi.b     #$30, d2            ; Converts binary number to ASCII code.
  224.  move.b     d2, (a0)+           ; Store the ASCII digit in array "decimal".
  225. loop_setup:
  226.  add.l      d0, d1              ; Restore the minuend.
  227.  moveq      #-1, d2             ; Pre-initialize subtractions counter to -1.
  228.  move.l     (a1)+, d0           ; Get next subtrahend.
  229.  bne.s      subtract            ; Loop back until subtrahend = 0.
  230.  move.b     #0, (a0)            ; Terminate decimal string with a null.
  231.  rts
  232. zero_passed:
  233.  move.b     #$20, (a0)+         ; Store a space in array "decimal".
  234.  move.b     #$30, (a0)+         ; Store an ASCII zero in array "decimal".
  235.  move.b     #0, (a0)            ; Terminate ASCII decimal string with a null.
  236.  rts
  237.  
  238.  data
  239. subtrahend:  dc.l   $3B9ACA00,$5F5E100,$989680,$F4240,$186A0,$2710,$3E8
  240.              dc.l   $64,$A,$1,$0
  241. heading:     dc.b   $D,$A,'PRG_3CP Execution Results',$D,$A,$D,$A,0
  242. message_1:   dc.b         '   Decimal value by repeated division method:    ',0
  243. message_2:   dc.b   $D,$A,'   Decimal value by repeated subtraction method: ',0
  244. newline:     dc.b $D,$A,0
  245.  bss
  246.  align                  ; Align storage on a word boundary.
  247. reversed:    ds.l    3  ; Temp buffer for the repeated division method.
  248. decimal:     ds.l    3  ; Output buffer, must be NULL terminated.
  249.              ds.l   24  ; Program stack, short enough for examination.
  250. stack:       ds.l    0  ; Address of program stack.
  251. program_end: ds.l    0  ; Marks the end of program memory.
  252.  end
  253.