home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / program / books / 68k_book / arp_src / prg_3cp.s < prev    next >
Text File  |  1985-11-20  |  17KB  |  370 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.  ;    This program is divided into two parts.  Part 1 verifies that the
  15.  ; results from two binary to ASCII decimal conversion algorithms are
  16.  ; identical.  The first conversion algorithm is called the "repeated
  17.  ; division" method; the number to be converted is repeatedly divided by 10.
  18.  ; The second algorithm is called the "repeated subtraction" method; powers
  19.  ; of ten are repeatedly subtracted from the number to be converted.
  20.  
  21.  ;    Part 2 compares the two algorithms to determine which is the faster.
  22.  
  23.  ;    Part 1 contains three sections.  Section 1 confirms that both algorithms
  24.  ; yield the same result for a positive number; section 2 confirms identical
  25.  ; results for a negative number; section 3 confirms identical results for
  26.  ; the number zero.
  27.  
  28.  ; A FEW NOTES:
  29.  
  30.  ; 1 - "clr.w  Dn" is one of the fastest ways to clear only the lower word
  31.  ;     of a data register.
  32.  
  33.  ; 2 - The stack used in the program is small enough to permit easy access
  34.  ;     to its contents via the AssemPro debugger.
  35.  
  36.  ; 3 - In the "repeated division" algorithm, a null character must be stored
  37.  ;     in the array "reversed" for proper operation of the
  38.  ;     "reversed_to_decimal" loop when the program is executed from AssemPro.
  39.  ;     This is true because AssemPro will not necessarily clear the array to
  40.  ;     zeroes.
  41.  
  42.  ;     When the program is executed from the desktop, however, the operating
  43.  ;     system will clear the array.  Therefore, if the program were intended
  44.  ;     for use such as it is, the instruction which stores the null at the
  45.  ;     end of the array "reversed" could be eliminated.
  46.  
  47.  ;     This is only one of the many types of adjustments
  48.  ;            which must be made when executing programs from debuggers.
  49.  
  50. calculate_program_size:
  51.  lea        program_end, a0     ; Put "end of program" address in A0.
  52.  movea.l    4(a7), a1           ; Put "basepage" address in A1.
  53.  suba.l     a1, a0              ; Subtract basepage address from A0.
  54.  lea        stack, a7           ; Point A7 to this program's stack.
  55.  
  56. return_memory:                  ; Return unused memory to operating system.
  57.  pea        (a0)                ; Store total program length in stack.
  58.  pea        (a1)                ; Store basepage address in stack.
  59.  move.l     #$4A0000, -(sp)     ; Function = m_shrink = GEMDOS $4A.
  60.  
  61.  ; NOTE: The above instruction is a combination of two that are often seen
  62.  ;       in references:
  63.  
  64.  ;       move.w     d0, -(sp)   ; Dummy value, can be anything.
  65.  ;       move.w     #$4a, -(sp) ; Function = m_shrink = GEMDOS $4A.
  66.  
  67.  trap       #1                  ; GEMDOS call.
  68.  lea        $C(sp), sp          ; Reset stack pointer to top of stack.
  69.  
  70. mainline:                       ; Marks the beginning of program proper.
  71.  lea        heading, a0         ; Print heading for program's output.
  72.  bsr        print_string
  73.  
  74.  ;
  75.  ; PART 1, SECTION 1: Conversion of a positive binary number to ASCII decimal.
  76.  ;
  77.  
  78.  lea        part_1_head, a0     ; Print PART 1 heading.
  79.  bsr        print_string
  80.  lea        sect_1_head, a0     ; Print SECTION 1 heading.
  81.  bsr        print_string
  82.                                
  83. repeated_division_1:
  84.  lea        division_head, a0   ; Print heading for division results.      
  85.  bsr        print_string       
  86.  move.l     #2147483647, d1     ; Number to be converted must be in D1.
  87.  bsr        bin_to_dec_1        ; ASCII decimal string stored in "decimal".
  88.  lea        decimal, a0         ; Print ASCII decimal string.     
  89.  bsr        print_string     
  90.  
  91.  ; NOTE: Remember, although the number we store in D1 appears to our eyes
  92.  ;       to be a very familiar decimal number, the computer does not see
  93.  ;       it that way.  It is the assembler that lets us see things that
  94.  ;       are palatable to us while we are programming, and which, during
  95.  ;       assembly, converts that which we like to something the computer
  96.  ;       likes.  And the computer likes binary.
  97.  
  98. repeated_subtraction_1:
  99.  lea        subtract_head, a0   ; Print heading for subtraction results.
  100.  bsr        print_string 
  101.  move.l     #2147483647, d1     ; Number to be converted must be in D1.
  102.  bsr        bin_to_dec_2        ; ASCII decimal string stored in "decimal". 
  103.  lea        decimal, a0         ; Print ASCII decimal string.
  104.  bsr        print_string 
  105.  bsr        print_newlines
  106.  
  107.  ;
  108.  ; PART 1, SECTION 2: Conversion of a negative binary number to ASCII decimal.
  109.  ;
  110.  
  111.  lea        sect_2_head, a0     ; Print SECTION 2 heading.
  112.  bsr        print_string
  113.  
  114. repeated_division_2:
  115.  lea        division_head, a0   ; Print heading for division results.      
  116.  bsr        print_string 
  117.  move.l     #-7483647, d1      
  118.  bsr        bin_to_dec_1       
  119.  lea        decimal, a0        
  120.  bsr        print_string       
  121.  
  122. repeated_subtraction_2:
  123.  lea        subtract_head, a0   ; Print heading for subtraction results.
  124.  bsr        print_string
  125.  move.l     #-7483647, d1 
  126.  bsr        bin_to_dec_2  
  127.  lea        decimal, a0
  128.  bsr        print_string
  129.  bsr        print_newlines
  130.  
  131.  ;
  132.  ; PART 1, SECTION 3: Conversion of binary number zero to ASCII decimal.
  133.  ;
  134.  
  135.  lea        sect_3_head, a0     ; Print SECTION 3 heading.
  136.  bsr        print_string
  137.  
  138. repeated_division_3:
  139.  lea        division_head, a0   ; Print heading for division results.      
  140.  bsr        print_string 
  141.  move.l     #0, d1         
  142.  bsr        bin_to_dec_1   
  143.  lea        decimal, a0    
  144.  bsr        print_string   
  145.  
  146. repeated_subtraction_3:
  147.  lea        subtract_head, a0   ; Print heading for subtraction results.
  148.  bsr        print_string
  149.  move.l     #0, d1           
  150.  bsr        bin_to_dec_2     
  151.  lea        decimal, a0      
  152.  bsr        print_string     
  153.  bsr        print_newlines
  154.  
  155.  ;
  156.  ; PART 2: Repeated division algorithm versus repeated subtraction algorithm
  157.  ;         execution speed comparision.  Each algorithm is executed 1000 times.
  158.  ;
  159.  
  160.  lea        part_2_head, a0     ; Print PART 2 heading.
  161.  bsr        print_string
  162.  
  163. repeated_division_method:
  164.  lea        div_time_head, a0
  165.  bsr        print_string
  166.  move.l     #9999, d7           ; D7 is counter for the push loop.
  167.  bsr        get_time            ; Value of system clock returned in D5.
  168.  move.l     d5, d6              ; Save time in scratch register.
  169. division_loop:
  170.  move.l     #1928374650, d1     ; Number to be converted to ASCII decimal.
  171.  bsr        bin_to_dec_1 
  172.  dbra       d7, division_loop   ; Loop 1000 times.
  173.  bsr        get_time            ; Get current value of system clock.
  174.  sub.l      d6, d5              ; Subtract beginning value from ending value.
  175.  mulu       #5, d5              ; Convert to milliseconds.
  176.  move.l     d5, d1              ; Transfer value for conversion to ASCII decimal.
  177.  bsr       bin_to_dec_2        ; Convert.
  178.  lea        decimal, a0         ; Print repeated division algorithm time.
  179.  bsr.s      print_string
  180.  lea        units_label, a0     ; Print time label.
  181.  bsr.s      print_string
  182.  
  183. repeated_subtraction_method:
  184.  lea        sub_time_head, a0
  185.  bsr.s      print_string
  186.  move.l     #9999, d7           ; D7 is counter for the push loop.
  187.  bsr        get_time            ; Value of system clock returned in D5.
  188.  move.l     d5, d6              ; Save time in scratch register.
  189. subtraction_loop:
  190.  move.l     #1928374650, d1     ; Number to be converted to ASCII decimal.
  191.  bsr        bin_to_dec_2 
  192.  dbra       d7, subtraction_loop; Loop 1000 times.
  193.  bsr        get_time            ; Get current value of system clock.
  194.  sub.l      d6, d5              ; Subtract beginning value from ending value.
  195.  mulu       #5, d5              ; Convert to milliseconds.
  196.  move.l     d5, d1              ; Transfer value for conversion to ASCII decimal.
  197.  bsr        bin_to_dec_2        ; Convert.
  198.  lea        decimal, a0         ; Print repeated division algorithm time.
  199.  bsr.s      print_string
  200.  lea        units_label, a0     ; Print time label.
  201.  bsr.s      print_string
  202.  
  203. wait_for_keypress:
  204.  move.w     #8, -(sp)           ; Function = c_necin = GEMDOS $8.
  205.  trap       #1                  ; GEMDOS call.
  206.  addq.l     #2, sp              ; Reposition stack pointer at top of stack.
  207.  
  208. terminate:
  209.  move.w     #0, -(sp)           ; Function = p_term_old = GEMDOS $0.
  210.  trap       #1                  ; GEMDOS call.
  211.  
  212.  ;
  213.  ; SUBROUTINES
  214.  ;
  215.  
  216. print_string:                   ; Expects address of string to be in A0.
  217.  move.l     a0, -(sp)           ; Push address of string onto stack.
  218.  move.w     #9, -(sp)           ; Function = c_conws = GEMDOS $9.
  219.  trap       #1                  ; GEMDOS call
  220.  addq.l     #6, sp              ; Reposition stack pointer.
  221.  rts
  222.  
  223. print_newlines:                 ; Prints 2 carriage returns and linefeeds.
  224.  pea        newlines            ; Push address of string onto stack.
  225.  move.w     #9, -(sp)           ; Function = c_conws = GEMDOS $9.
  226.  trap       #1                  ; GEMDOS call
  227.  addq.l     #6, sp
  228.  rts
  229.  
  230.  ; Get_time subroutine.  Returns current value of system clock in D5.
  231.  
  232.  ; The get_time subroutine obtains the current value of the system variable
  233.  ; _hz_200 (memory location $4BA).  This variable is incremented every 200
  234.  ; hertz, which means that the period between increments is 5 milliseconds
  235.  ; (1/200 = .005).  In turn, this means that the variable measures time with 
  236.  ; a resolution of 5 milliseconds.
  237.  
  238.  ; Use this subroutine to measure the elapsed time of an event as follows:
  239.  
  240.  ; 1. Read and store the content of $4BA at the beginning of the event.
  241.  ; 2. At the conclusion of the event, read the content of $4BA again.
  242.  ; 3. Subtract the first value from the second.  This yields the number of
  243.  ;    5 millisecond intervals which occurred during the event.
  244.  ; 4. Multiply the difference by 5 to convert the elapsed time to milliseconds.
  245.  
  246. get_time:                       ; Get number of 5 msec periods.
  247.  move.l     #0, -(sp)           ; The zero turns on supervisor mode.
  248.  move.w     #$20, -(sp)         ; Function = super = GEMDOS $20.
  249.  trap       #1                  ; Go to supervisor mode.
  250.  addq.l     #6, sp              ; Supervisor stack pointer returned in D0.
  251.  move.l     $4BA, d5            ; Copy system time into register D5
  252.  move.l     d0, -(sp)           ; Restore supervisor stack pointer.
  253.  move.w     #$20, -(sp)         ; Function = super = GEMDOS $20.
  254.  trap       #1                  ; Go to user mode.
  255.  addq.l     #6, sp              ; Reset stack pointer to top of stack.
  256.  rts
  257.  
  258.  ; The binary to ASCII decimal conversion subroutine uses an algorithm
  259.  ; based on the "repeated division" algorithm discussed in chapter 9 of the
  260.  ; Ford & Topp book; however, the algorithm used here is not limited to a
  261.  ; 16-bit binary number.  There is a similar algorithm in the Atari section
  262.  ; of appendix B in the Skinner book. The divisor is decimal 10.
  263.  
  264. bin_to_dec_1:                   ; Converts 32-bit binary number in D1 to
  265.                                 ; ASCII decimal.
  266.  lea        decimal, a0         ; Point to beginning of array "decimal".
  267.  lea        reversed + 10, a1   ; Point to end of array "reversed".
  268.  move.b     #0, (a1)            ; Put a null at the end of the array.
  269. _get_sign:
  270.  tst.l      d1                  ; Is binary number positive, negative or zero?
  271.  beq.s      _zero_passed        ; Branch if number is 0.
  272.  bpl.s      _positive           ; Branch if positive.
  273.  move.b     #$2D, (a0)+         ; Store a minus sign in array decimal.
  274.  neg.l      d1                  ; Change number from negative to positive.
  275.  bra.s      _division_loop
  276. _positive:                      ; Branch to here when number is positive.
  277.  move.b     #$20, (a0)+         ; Store a space in array decimal.
  278. _division_loop:
  279.  move.w     d1, d2              ; Store lower word in temp register D2.
  280.  clr.w      d1                  ; Clear lower word.  
  281.  swap       d1                  ; Move higher word to lower word.
  282.  divu       #10, d1             ; Divide full 32 bits by ten.
  283.  move.w     d1, d3              ; Store quotient in temp register D3.
  284.  move.w     d2, d1              ; Combine lower word with remainder.
  285.  divu       #10, d1             ; Divide full 32 bits by ten.
  286.  swap       d1                  ; Swap quotient and remainder words.
  287. _convert_to_ascii:              ; Convert digit to ASCII and store it.
  288.  addi.b     #$30, d1            ; Convert digit to ASCII.
  289.  move.b     d1, -(a1)           ; Store the digit in array "reversed".
  290.  move.w     d3, d1              ; Bring in higher word quotient. 
  291.  swap       d1                  ; Swap high and low word quotients.
  292.  tst.l      d1                  ; Is content of D1 zero yet?
  293.  bne.s      _division_loop      ; Continue until content of D1 is zero.
  294. reversed_to_decimal:            ; Transfer contents of "reversed" to "decimal".
  295.  move.b     (a1)+, (a0)+        ; Loop until the null is transfered.
  296.  bne.s      reversed_to_decimal
  297.  rts
  298. _zero_passed:
  299.  move.b     #$20, (a0)+         ; Store a space in array "decimal".
  300.  move.b     #$30, (a0)+         ; Store the zero in array "decimal".
  301.  move.b     #0, (a0)            ; Terminate the decimal string with a null.
  302.  rts
  303.  
  304.  ; Conversion from binary to ASCII decimal using repeated subtraction.
  305.  ; See documentation in program PRG_3AP.S.
  306.  
  307. bin_to_dec_2:                  
  308.  lea        decimal, a0         ; Put address of array "decimal" in A0.
  309.  lea        subtrahend, a1      ; Put address of subtrahend table in A1.
  310.  move.l     (a1)+, d0           ; Put first subtrahend in D0.
  311.  move.b     #$30, d2            ; Initialize subtractions counter to ASCII zero.
  312. get_sign:
  313.  tst.l      d1                  ; Is binary number positive, negative or zero?
  314.  beq.s      zero_passed         ; Branch if number is 0.
  315.  bpl.s      positive            ; Branch if positive.
  316.  move.b     #$2D, (a0)+         ; Store a minus sign in array "decimal".
  317.  neg.l      d1                  ; Change binary number from neg to pos.
  318.  bra.s      discard_leading_zeroes
  319. positive:                       ; Branch to here when number is positive.
  320.  move.b     #$20, (a0)+         ; Store a space in array decimal.
  321. discard_leading_zeroes:         ; Subtract subtrahend from minuend.
  322.  sub.l      d0, d1              ; Loop till difference is positive,
  323.  bpl.s      subtract            ; indicating that digit is not zero.
  324.  add.l      d0, d1              ; Restore minuend.
  325.  move.l     (a1)+, d0           ; Get next subtrahend.
  326.  bra.s      discard_leading_zeroes
  327. subtract:
  328.  addq.b     #1, d2              ; Increment subtractions counter.
  329.  sub.l      d0, d1              ; Subtract subtrahend from D1.
  330.  bpl.s      subtract            ; Loop until D1 becomes negative.
  331.  move.b     d2, (a0)+           ; Store the ASCII digit in array "decimal".
  332. loop_setup:
  333.  add.l      d0, d1              ; Restore the minuend.
  334.  move.b     #$2F, d2            ; Pre-initialize subtractions counter to $30-1.
  335.  move.l     (a1)+, d0           ; Get next subtrahend.
  336.  bne.s      subtract            ; Loop back until subtrahend = 0.
  337.  move.b     #0, (a0)            ; Terminate decimal string with a null.
  338.  rts
  339. zero_passed:
  340.  move.b     #$20, (a0)+         ; Store a space in array "decimal".
  341.  move.b     d2, (a0)+           ; Store an ASCII zero in array "decimal".
  342.  move.b     #0, (a0)            ; Terminate ASCII decimal string with a null.
  343.  rts
  344.  
  345.  data
  346. subtrahend:    dc.l $3B9ACA00,$5F5E100,$989680,$F4240,$186A0,$2710,$3E8
  347.                dc.l $64,$A,$1,$0
  348. heading:       dc.b 'PRG_3CP Execution Results',$D,$A,$D,$A,0
  349. part_1_head:   dc.b '  Part 1: Conversion Verification',$D,$A,$D,$A,0
  350. sect_1_head:   dc.b '    Section 1: Positive Number Conversion',$D,$A,$D,$A,0
  351. sect_2_head:   dc.b '    Section 2: Negative Number Conversion',$D,$A,$D,$A,0
  352. sect_3_head:   dc.b '    Section 3: Converson for Zero',$D,$A,$D,$A,0
  353. division_head: dc.b '      Decimal value by repeated division method:    ',0
  354. subtract_head: dc.b $D,$A
  355.                dc.b '      Decimal value by repeated subtraction method: ',0
  356. part_2_head:   dc.b '  Part 2: Execution Speed Results',$D,$A,$D,$A,0
  357. time_head:     dc.b '    Times for 1000 executions of each conversion method.',0
  358. div_time_head: dc.b '      Elapsed time for repeated division method:    ',0
  359. sub_time_head: dc.b '      Elapsed time for repeated subtraction method: ',0
  360. units_label:   dc.b ' milliseconds',$D,$A,0
  361. newlines:      dc.b $D,$A,$D,$A,0
  362.  bss
  363.  align                  ; Align storage on a word boundary.
  364. reversed:    ds.l    3  ; Temp buffer for the repeated division method.
  365. decimal:     ds.l    3  ; Output buffer, must be NULL terminated.
  366.              ds.l   24  ; Program stack, short enough for examination.
  367. stack:       ds.l    0  ; Address of program stack.
  368. program_end: ds.l    0  ; Marks the end of program memory.
  369.  end