ASMB,L,C,R
      HED HASH SUBROUTINE FOR IMAGE/1000
      NAM HASH,7 92069-16157 REV.1912 790130
* 
* 
******************************************************************* 
* (C) COPYRIGHT HEWLETT-PACKARD COMPANY 1979. ALL RIGHTS RESERVED.
* NO PART OF THIS PROGRAM MAY BE PHOTOCOPIED, REPRODUCED, OR
* TRANSLATED TO ANOTHER PROGRAM LANGUAGE WITHOUT THE PRIOR WRITTEN
* CONSENT OF HEWLETT-PACKARD COMPANY. 
******************************************************************* 
* 
* 
*     SOURCE:    92069-18157
*     RELOC:     92069-16157
* 
*     PRGMR:     CEJ
* 
* 
******************************************************************* 
* 
* 
* 
*  Hash is a doubleword integer function which accepts a key item value 
*  (either real, integer, or character string) and transforms the value 
*  into a doubleword positive integer.  Hash performs the following func- 
*  tion.
* 
*    1)  Running function value = first doubleword in value.  If odd # of 
*        words in value, pad first word of Running function value with
*        nulls to make item an integeral number of doublewords long.
*    2)  Shift Running function value left logically by 1.
*    3)  If no words remaining in item value then go to 9.
*    4)  Doubleword = last remaining doubleword of item value (work with
*        doublewords beginning at the right end and working left from here
*        on out). 
*    5)  Rotate Running function value left circular by:
*             (MOD(Doubleword,31) + 1). 
*    6)  Running function value = Running function value + Doubleword.
*    7)  Go to 4. 
*    8)  Shift function value logically right by 1 (make sure value is
*        positive). 
*    9)  Return - function value in A & B registers.
* 
*  The calling sequence for HASH is:
* 
*             JSB HASH
*              DEF *+3      return point
*              DEF LENTH    item length in words
*              DEF VALUE    item value
* 
      EXT .DAD,.ENTR
      ENT HASH
A     EQU 0 
B     EQU 1 
* 
LENTH NOP 
VALUE NOP 
* 
*  Get true parameter and return addresses
* 
HASH  NOP 
      JSB .ENTR 
       DEF LENTH
* 
*  Determine doubleword counter with item length. 
* 
      LDA LENTH,I 
      INA           # of doublewords = # of words 
      ARS             plus one divided by two.
      CMA,INA       Negate for easy loop counting.
      STA #DBWS 
* 
*  Calculate address of last doublewrod in item.
* 
      LDA VALUE     Last doubleword address = 
      ADA LENTH,I     address of beginning of item plus 
      ADA M2          length of item minus two. 
      STA LAST
* 
*  Get first doubleword in item.  If odd # of words in item, compensate 
*  for the missing word by padding the item with preceding nulls. 
* 
      LDA LENTH,I   If odd # words
      SLA,RSS         (least significant bit set) 
      JMP HASH3 
      CLA             set first word of first doubleword
      LDB VALUE,I     to zero and second word to first
      JMP HASH4       word of item value. 
* 
HASH3 DLD VALUE,I   Else, use what is there.
* 
*  Logically shift the doubleword value left 1 bit. 
* 
HASH4 CLE,ELB       E<-bit 15 of B,bit 0 of B<-0
      ELA           bit 0 of A<-E=bit 15 of B 
* 
*  This becomes the running function value. 
* 
      DST RSULT 
* 
*               ENTER MAIN LOOP HERE
*  See if any doublewords left in item. 
* 
HASH5 ISZ #DBWS 
      RSS 
      JMP HASH7     If not, we are almost done. 
* 
*  Get the rightmost remaining doubleword in item.  (From here on out,
*  all doublewords are picked up from the end of the item working towards 
*  the beginning.)
* 
      LDA LAST
      LDB A,I 
      INA 
      LDA A,I 
* 
*  Calculate MOD of the doubleword by 31. 
* 
*  This code is somewhat cryptic, but performs the following: 
* 
*    Get the 20 most significant bits of the doubleword and 
*      make them the 20 least significant bits, extending the sign. 
*    Divide them by 31. 
*    Save the remainder in the B register.
*    Get the remaining 12 least significant bits of the doubleword
*      and concatenate them onto the remainder in the B register as 
*      the 12 least significant bits. 
*    Divide this by 31. 
*    If the remainder in the B register is now negative add 31 to it
*      to get the true MOD. 
* 
*  The above order of processing is followed because, in the case of a
*  doubleword whose absolute maginitude is larger than 2**19-1, the DIV 
*  instruction might not perform properly since the quotient could be 
*  larger than 2**15-1. 
* 
      ASR 12        Shift out least significant 12 bits.
      DIV D31       First divide. 
* 
      LDA LAST      Get the least significant 
      INA             12 bits back again. 
      LDA A,I       (We just discard the quotient.) 
      ALF 
* 
      ASR 4         Concatenate with the remainder. 
      DIV D31       Second divide.
      SSB 
      ADB D31       B = true MOD. 
* 
*  Get the rotate count by adding one to the above computed MOD.
* 
      INB 
      STB RCNT
*  Rotate the running function value left circular by MOD + 1.
* 
*  This code is also somewhat cryptic, but performs the following:
* 
*    If (RCNT > 16) 
*      Then Begin:
*        RCNT := RCNT - 16
*        Swap high and low order words of running value.
*      End
*    Rotate running value left circular by RCNT.
* 
      LDA RCNT
      LDB RSULT+1   B = 2nd word of running value.
      ADA M17       See if RCNT <= 16.
      SSA,INA 
      JMP HASH6       yes - simple case of rotate 
* 
      STA RCNT        no - swap high & low order words. 
      LDA RSULT     A = 1st word of running value 
      STB RSULT     Put 2nd word into first word area.
      LDB A         B = new 2nd word of running value.
      LDA RCNT      Get remainder of ((MOD + 1) - 16).
* 
HASH6 AND LOFOR     Only the low 4 bits of RCNT are meaningful. 
      IOR RRL16     Form the rotate instruction.
      STA INSTR     Put it into the Run Time code.
      LDA RSULT     A = first word of running value.
INSTR ABS *-*       <<Rotate instruction goes here!!>>
* 
*  Add in the doubleword used in the MOD and this becomes the new running 
*  function value.
* 
      JSB .DAD
       DEF LAST,I 
      DST RSULT 
* 
*  Get address of next to last used doubleword in item and repeat for each
*  doubleword in item.
* 
      LDA LAST
      ADA M2
      STA LAST
      JMP HASH5 
* 
*  When loop is finished, shift the result right logically one bit to 
*  clear sign bit (result must be positive) and return. 
* 
HASH7 DLD RSULT 
      CLE,ERA 
      ERB 
      JMP HASH,I
* 
*  Constants and variables
* 
M17   DEC -17 
M2    DEC -2
D31   DEC 31
LOFOR OCT 000017
* 
RSULT BSS 2 
RRL16 RRL 16        Used to create Run Time rotate instruction. 
#DBWS NOP 
LAST  NOP 
RCNT  NOP 
      END 
                                                                                                                                                                                                                          