SMAL32 (rev 10/08) "mp4.a - long-int class im 17:04:26 Page 1 Thu Oct 29 2009 20 SUBTITLE "integer-long conversions and copy" 91 SUBTITLE "add and subtract" 125 SUBTITLE "multiply" 178 SUBTITLE "divide and mod" SMAL32 (rev 10/08) "mp4.a - long-int class im 17:04:26 Page 2 Thu Oct 29 2009 1 TITLE "mp4.a - long-int class implementation" 2 ; by Douglas Jones -- Oct 27, 2009 3 4 USE "hawk.macs" 5 6 ; long integers are described as follows 7 LOW = 0 ; the least significant 32 bits 8 HIGH = 4 ; the most significant 32 bits 9 LONGSIZE= 8 ; size of a long 10 11 ; documentation is summarized in mp4.h, quoted as follows: 12 13 ; all methods conform to the normal Hawk calling conventions 14 ; link through R1, 15 ; use R2 as a stack pointer 16 ; use R3-up as parameters 17 ; guarantee R2 and R7-15 are restored on return 18 ; registers R3-R7, if unspecified as return values, may be wiped out 19 SMAL32 (rev 10/08) "mp4.a - long-int class im 17:04:26 Page 3 "integer-long conversions Thu Oct 29 2009 20 SUBTITLE "integer-long conversions and copy" 21 ; ---------------------------------- 22 INT INT2LONG ; integer to long conversion 23 INT2LONG: 24 ; given R3 - pointer to long 25 ; given R4 - 2's complement integer value 26 ; returns R3 - pointer to long, with given value 27 ; sets the long to the indicated integer value 28 STORES R4,R3 ; store low half +000000: F4 A3 29 SR R4,16 +000002: 94 00 30 SR R4,16 +000004: 94 00 31 STORE R4,R3,HIGH ; high half is sign extended +000006: F4 23 0004 32 JUMPS R1 ; return +00000A: F0 B1 33 34 ; ---------------------------------- 35 INT LONG2INT ; long to integer conversion 36 LONG2INT: 37 ; given R3 - pointer to long 38 ; returns R3 - integer value if the long value fits 39 ; returns R4 - error flag, 0 if it fits, 1 if not 40 LOAD R4,R3,HIGH ; high half +00000C: F4 53 0004 41 LOADS R3,R3 ; low half is return value +000010: F3 D3 42 43 ; now, the problem is to detect out-of-range conditions 44 MOVE R5,R3 ; copy return value +000012: F5 F3 45 SR R5,16 +000014: 95 00 46 SR R5,16 ; sign extend low half +000016: 95 00 47 SUB R4,R4,R5 ; gives nonzero value for overflow +000018: 24 45 48 BZS L2IQT +00001A: 02 01 49 LIS R4,1 ; convert nonzero values to 1 +00001C: D4 01 50 L2IQT: 51 JUMPS R1 ; return +00001E: F0 B1 52 53 ; ---------------------------------- 54 INT LONGCOPY ; copy one long to another 55 LONGCOPY: 56 ; given R3 - pointer to long destination 57 ; given R4 - pointer to long source 58 ; returns R3 - the pointer is not changed, but referent updated 59 LOADS R5,R4 +000020: F5 D4 60 STORES R5,R3 ; copy low half +000022: F5 A3 61 LOAD R5,R4,HIGH +000024: F5 54 0004 62 STORE R5,R3,HIGH ; copy high half +000028: F5 23 0004 63 JUMPS R1 ; return +00002C: F0 B1 64 65 ; ---------------------------------- 66 INT LONGCMP ; compare two longs 67 LONGCMP: 68 ; given R3 - pointer to long a 69 ; given R4 - pointer to long b 70 ; returns R3 - -1 if a < b, 0 if a=b, +1 if a > b 71 LOAD R5,R3,HIGH +00002E: F5 53 0004 72 LOAD R6,R4,HIGH +000032: F6 54 0004 73 CMP R5,R6 +000036: 20 56 74 BGT LCMPRP SMAL32 (rev 10/08) "mp4.a - long-int class im 17:04:26 Page 4 "integer-long conversions Thu Oct 29 2009 +000038: 0E 08 75 BLT LCMPRN ; compare high halves +00003A: 05 09 76 LOADS R5,R3 +00003C: F5 D3 77 LOADS R6,R4 +00003E: F6 D4 78 CMP R5,R6 +000040: 20 56 79 BGTU LCMPRP +000042: 0F 03 80 BLTU LCMPRN ; compare low halves +000044: 0C 04 81 LIS R3,0 +000046: D3 00 82 BR LCMPQT ; return zero +000048: 00 03 83 LCMPRP: 84 LIS R3,1 +00004A: D3 01 85 BR LCMPQT ; return positive +00004C: 00 01 86 LCMPRN: 87 LIS R3,-1 ; return negative +00004E: D3 FF 88 LCMPQT: 89 JUMPS R1 ; return +000050: F0 B1 90 SMAL32 (rev 10/08) "mp4.a - long-int class im 17:04:26 Page 5 "add and subtract" Thu Oct 29 2009 91 SUBTITLE "add and subtract" 92 ; ---------------------------------- 93 INT LONGADD ; add two longs 94 LONGADD: 95 ; given R3 - pointer to long augend 96 ; given R4 - pointer to long addend 97 ; returns R3 - the pointer is not changed, but referent now holds sum 98 LOADS R5,R3 ; get augend low +000052: F5 D3 99 LOADS R6,R4 ; get addend low +000054: F6 D4 100 ADD R5,R5,R6 ; add low halves +000056: 35 56 101 STORES R5,R3 ; save low half of sum - C unchanged +000058: F5 A3 102 LOAD R5,R3,HIGH ; get augend high - C unchanged +00005A: F5 53 0004 103 LOAD R6,R4,HIGH ; get addend high - C unchanged +00005E: F6 54 0004 104 ADDC R5,R6 ; add high halves +000062: 15 76 105 STORE R5,R3,HIGH ; save high half of sum +000064: F5 23 0004 106 JUMPS R1 ; return +000068: F0 B1 107 108 ; ---------------------------------- 109 INT LONGSUB ; subtract two longs 110 LONGSUB: 111 ; given R3 - pointer to long minuend 112 ; given R4 - pointer to long subtrahend 113 ; given R3 - pointer to long augend 114 ; returns R3 - the pointer is not changed, referent now is difference 115 LOADS R5,R3 ; get minuend low +00006A: F5 D3 116 LOADS R6,R4 ; get subtrahend low +00006C: F6 D4 117 SUB R5,R5,R6 ; subtract low halves +00006E: 25 56 118 STORES R5,R3 ; save low half of difference - C unchanged +000070: F5 A3 119 LOAD R5,R3,HIGH ; get minuend high - C unchanged +000072: F5 53 0004 120 LOAD R6,R4,HIGH ; get subtrahend high - C unchanged +000076: F6 54 0004 121 SUBB R5,R6 ; subtract high halves +00007A: 15 66 122 STORE R5,R3,HIGH ; save high half of difference +00007C: F5 23 0004 123 JUMPS R1 ; return +000080: F0 B1 124 SMAL32 (rev 10/08) "mp4.a - long-int class im 17:04:26 Page 6 "multiply" Thu Oct 29 2009 125 SUBTITLE "multiply" 126 ; ---------------------------------- 127 INT LONGMUL ; multiply two longs 128 ; activation record 129 R8SAVE = 0 ; save location for R8 130 R9SAVE = 4 ; save location for R9 131 R10SAVE = 8 ; save location for R10 132 ARSIZE = 12 133 134 LONGMUL: 135 ; given R3 - pointer to multiplicand 136 ; given R4 - pointer to multiplier 137 ; returns R3 - the pointer is not changed, but referent now is product 138 STORES R8,R2 ; save R8 +000082: F8 A2 139 STORE R9,R2,R9SAVE ; save R9 +000084: F9 22 0004 140 STORE R10,R2,R10SAVE ; save R10 +000088: FA 22 0008 141 LOAD R5,R4,HIGH ; get high multiplier +00008C: F5 54 0004 142 LOADS R4,R4 ; get low multiplier +000090: F4 D4 143 LOADS R8,R3 ; get low multiplicand +000092: F8 D3 144 LOAD R9,R3,HIGH ; get high multiplicand +000094: F9 53 0004 145 146 ; code based on TIMESL from Chapter 13, hawk manual 147 LIS R6,0 ; -- low +000098: D6 00 148 LIS R7,0 ; product = 0 -- high +00009A: D7 00 149 ; -- first, special multiply step for sign bit 150 SL R4,1 ; -- low +00009C: A4 01 151 ROL R5 ; multiplier = multiplier << 1 -- high +00009E: 15 75 152 BCR LMSSKP ; if multiplier sign was 1 { +0000A0: 0C 02 153 SUB R6,R6,R8 ; - low +0000A2: 26 68 154 SUBB R7,R9 ; product = product - multiplicand - high +0000A4: 17 69 155 LMSSKP: ; } 156 LIS R10,63 ; -- 63 non-sign bits remain to be processed +0000A6: DA 3F 157 LMSLLP: ; for (i = 63; i > 0; i--) { 158 ; -- regular multiply step for 63 more bits 159 SL R6,1 ; -- low +0000A8: A6 01 160 ROL R7 ; product = product << 1 -- high +0000AA: 17 77 161 SL R4,1 ; -- low +0000AC: A4 01 162 ROL R5 ; multiplier = multiplier << 1 -- high +0000AE: 15 75 163 BCR LMSLCN ; if high bit was 1 { +0000B0: 0C 02 164 ADD R6,R6,R8 ; -- low +0000B2: 36 68 165 ADDC R7,R9 ; product = product + multiplicand -- high +0000B4: 17 79 166 LMSLCN: ; } 167 ADDSI R10,-1 +0000B6: 1A CF 168 BGT LMSLLP ; } +0000B8: 0E F7 169 ; end of code based on TIMESL from Chapter 13, hawk manual 170 171 STORES R6,R3 ; save low product +0000BA: F6 A3 172 STORE R7,R3,HIGH ; save high product +0000BC: F7 23 0004 173 LOADS R8,R2 ; restore R8 +0000C0: F8 D2 174 LOAD R9,R2,R9SAVE ; restore R9 +0000C2: F9 52 0004 175 LOAD R10,R2,R10SAVE ; restore R10 +0000C6: FA 52 0008 176 JUMPS R1 ; return +0000CA: F0 B1 177 SMAL32 (rev 10/08) "mp4.a - long-int class im 17:04:26 Page 7 "divide and mod" Thu Oct 29 2009 178 SUBTITLE "divide and mod" 179 ; ---------------------------------- 180 INT LONGDIV ; divide two longs 181 COMMON LONGREMS,LONGSIZE 182 ; activation record 183 R8SAVE = 0 ; save location for R8 184 R9SAVE = 4 ; save location for R9 185 R10SAVE = 8 ; save location for R10 186 R11SAVE = 12 ; save location for R11 187 ARSIZE = 16 188 189 LONGDIV: 190 ; given R3 - pointer to dividend 191 ; given R4 - pointer to divisor 192 ; returns R3 - the pointer is not changed, but referent now is quotient 193 STORES R8,R2 ; save R8 +0000CC: F8 A2 194 STORE R9,R2,R9SAVE ; save R9 +0000CE: F9 22 0004 195 STORE R10,R2,R10SAVE ; save R10 +0000D2: FA 22 0008 196 STORE R11,R2,R11SAVE ; save R11 +0000D6: FB 22 000C 197 198 LOAD R5,R4,HIGH ; get high divisor +0000DA: F5 54 0004 199 LOADS R4,R4 ; get low divisor +0000DE: F4 D4 200 LOADS R6,R3 ; get low dividend +0000E0: F6 D3 201 LOAD R7,R3,HIGH ; get high dividend +0000E2: F7 53 0004 202 203 ; -- take absolute values and remember if should negate quotient 204 LIS R11,0 ; negate = 0 +0000E6: DB 00 205 TESTR R5 +0000E8: F0 E5 206 BNR LDIVSN ; if (divisor < 0) { +0000EA: 09 04 207 NOT R5 +0000EC: 15 90 208 NEG R4,R4 ; -- low +0000EE: 24 04 209 ADDC R5,R0 ; divisor = - divisor -- high +0000F0: 15 70 210 ADDSI R11,1 ; negate = negate + 1 +0000F2: 1B C1 211 LDIVSN: ; } 212 TESTR R7 +0000F4: F0 E7 213 BNR LDIVDN ; if (dividend < 0) { +0000F6: 09 04 214 NOT R7 +0000F8: 17 90 215 NEG R6,R6 ; -- low +0000FA: 26 06 216 ADDC R7,R0 ; dividend = - dividend -- high +0000FC: 17 70 217 ADDSI R11,5 ; negate = negate + 5 +0000FE: 1B C5 218 LDIVDN: ; } 219 ; -- negate bit 0 means must negate quotient 220 ; -- negate bit 2 means must negate remainder 221 222 ; code based on DIVIDEU from Chapter 13, hawk manual 223 LIS R8,0 ; -- low +000100: D8 00 224 LIS R9,0 ; remainder = 0 -- high +000102: D9 00 225 LIS R10,64 +000104: DA 40 226 227 LDIVLP: ; for (i = 64; i > 0; i--) { -- 64 divide steps 228 SL R6,1 ; -- lowest +000106: A6 01 229 ROL R7 ; -- lower +000108: 17 77 230 ROL R8 ; -- higher +00010A: 18 78 231 ROL R9 ; remainder_quotient = remainder_quotient<<1 +00010C: 19 79 232 CMP R9,R5 SMAL32 (rev 10/08) "mp4.a - long-int class im 17:04:26 Page 8 "divide and mod" Thu Oct 29 2009 +00010E: 20 95 233 BLTU LDIVUC ; -- high +000110: 0C 05 234 CMP R8,R4 +000112: 20 84 235 BLTU LDIVUC ; if (remainder >= divisor) { -- low +000114: 0C 03 236 SUB R8,R8,R4 ; -- low +000116: 28 84 237 SUBB R9,R5 ; remainder = remainder - divisor -- high +000118: 19 65 238 ADDSI R6,1 ; quotient = quotient + 1 (no carry needed) +00011A: 16 C1 239 LDIVUC: ; } 240 241 ADDSI R10,-1 +00011C: 1A CF 242 BGT LDIVLP ; } +00011E: 0E F3 243 ; end of code based on DIVIDEU from Chapter 13, hawk manual 244 245 ; -- see if should negate quotient or remainder 246 BITTST R11,0 +000120: 90 B1 247 BCR LDIVQN ; if (negate bit 0 set) { +000122: 0C 03 248 NOT R7 +000124: 17 90 249 NEG R6,R6 +000126: 26 06 250 ADDC R7,R0 ; quotient = - quotient +000128: 17 70 251 LDIVQN: ; } 252 BITTST R11,2 +00012A: 90 B3 253 BCR LDIVRN ; if (negate bit 2 set) { +00012C: 0C 03 254 NOT R9 +00012E: 19 90 255 NEG R8,R8 +000130: 28 08 256 ADDC R9,R0 ; remainder = - remainder +000132: 19 70 257 LDIVRN: ; } 258 259 STORES R6,R3 ; save low quotient +000134: F6 A3 260 STORE R7,R3,HIGH ; save high quotient +000136: F7 23 0004 261 LIL R11,LONGREMS +00013A: EB +000000 262 STORES R8,R11 ; save low remainder +00013E: F8 AB 263 STORE R9,R11,HIGH ; save high remainder +000140: F9 2B 0004 264 LOADS R8,R2 ; restore R8 +000144: F8 D2 265 LOAD R9,R2,R9SAVE ; restore R9 +000146: F9 52 0004 266 LOAD R10,R2,R10SAVE ; restore R10 +00014A: FA 52 0008 267 LOAD R11,R2,R11SAVE ; restore R11 +00014E: FB 52 000C 268 JUMPS R1 ; return +000152: F0 B1 269 270 ; ---------------------------------- 271 INT LONGMOD ; get remainder from most recent division 272 LONGMOD: 273 ; given R3 - pointer to destination 274 ; returns R3 - the pointer is not changed, but referent is remainder 275 LIL R6,LONGREMS +000154: E6 +000000 276 LOADS R4,R6 ; get low remainder +000158: F4 D6 277 LOAD R5,R6,HIGH ; get high remainder +00015A: F5 56 0004 278 STORES R4,R3 ; save low remainder +00015E: F4 A3 279 STORE R5,R3,HIGH ; save high remainder +000160: F5 23 0004 280 JUMPS R1 ; return +000164: F0 B1 281 282 END no errors