welcome: please sign in
location: attachment:useful_functions.asm of UsefulFunctions

Attachment 'useful_functions.asm'

Download

   1 ; useful_functions.asm - a listing of useful functions in assembly for
   2 ; microdec programming.  register limitations are shown for each program.
   3 
   4 ; to use these, just copy and paste into your program, and be sure that your
   5 ; register usage doesnt overlap. a listing of all your register usage at the
   6 ; beginning of your file is a good way to check for this.  be sure to replace
   7 ; UID with your unique id for your code, or you will get assembly conflicts.
   8 ; check the microdec wiki to see which numbers have been assigned.  if other
   9 ; people use your code, it shouldnt conflict with their assembly either.
  10 
  11 ; list of functions in this file
  12 ;
  13 ; 1.  reading and writing to the codec.
  14 ; 2.  reading from the sram - 16b
  15 ; 3.  reading from the sram - 18b
  16 ; 4.  writing to the sram - 16b
  17 ; 5.  writing to the sram - 18b
  18 ; 6.  sampling the switch to change functions - no initialization
  19 ; 7.  sampling the switch to change functions - with initialization
  20 ; 8.  initialization routine
  21 ; 9.  16b signed x 16b signed to (16b or 32b) signed number
  22 ; 10. 16b signed x 8b unsigned to (16b or 24b) signed number
  23 ; 11. 16b signed x 16b unsigned to (16b or 32b) signed number
  24 ; 12. two's complement of 16b number
  25 ; 13. two's complement of 24b number
  26 ; 14. adding signed numbers of different lengths
  27 
  28 ; 1. reading and writing to the codec.
  29 ;
  30 ; this function will write 16b stereo data to the codec, and read out 16b
  31 ; stereo data from the codec.  this function must be run at a fixed interval,
  32 ; or audio glitches will be heard. you must read and write all 16b of both
  33 ; channels each time, or the codec will not operate.  you can change the bit
  34 ; depth for the codec, and its rate in the setup registers in the main file.
  35 ; only 16b stereo data has been tested at this point (both 44.1kHz and 48khz
  36 ; have been tested, but the microdec hardware only supports 44.1kHz). this
  37 ; function assumes you have the spi register configured appropriately (the
  38 ; main file does this).
  39 
  40 ; register usage:
  41 ;
  42 ; r2  left lsb out - can be any register
  43 ; r3  left msb out - can be any register
  44 ; r4  right lsb out - can be any register
  45 ; r5  right msb out - can be any register
  46 ; r6  left lsb in - can be any register
  47 ; r7  left msb in - can be any register
  48 ; r8  right lsb in - can be any register
  49 ; r9  right msb in - can be any register
  50 ; r17 temporary swap register - can be any register
  51 
  52 ; code:
  53 ;
  54 ;the timing of this first operation is critical. do not change the next
  55 ;three lines for any reason.
  56 sbi portb,portb0 ; toggle slave select pin to begin transfer
  57 out spdr,r3 ; send out left channel msb
  58 cbi portb,portb0 ; clear slave select pin
  59 ;
  60 ;more code can be placed here to save cycles, up to 16 lines without much
  61 ;effect on the total time that it takes to run this code.
  62 ;
  63 wait1_UID: ; check if byte has been sent
  64 
  65 in r17,spsr
  66 sbrs r17,spif
  67 rjmp wait1_UID
  68 in r7,spdr ; recieve in left channel msb
  69 out spdr,r2 ; send out left channel lsb
  70 ;
  71 ;more code can be placed here to save cycles, up to 16 lines without much
  72 ;effect on the total time that it takes to run this code.
  73 ;
  74 wait2_UID: ; check if byte has been sent
  75 
  76 in r17,spsr
  77 sbrs r17,spif
  78 rjmp wait2_UID
  79 in r6,spdr ; recieve in left channel lsb
  80 out spdr,r5 ; send out right channel msb
  81 ;
  82 ;more code can be placed here to save cycles, up to 16 lines without much
  83 ;effect on the total time that it takes to run this code.
  84 ;
  85 wait3_UID: ; check if byte has been sent
  86 
  87 in r17,spsr
  88 sbrs r17,spif
  89 rjmp wait3_UID
  90 in r9,spdr ; recieve in right channel msb
  91 out spdr,r4 ; send out right channel lsb
  92 ;
  93 ;more code can be placed here to save cycles, up to 16 lines without much
  94 ;effect on the total time that it takes to run this code.
  95 ;
  96 wait4_UID: ; check if byte has been sent
  97 
  98 in r17,spsr
  99 sbrs r17,spif
 100 rjmp wait4_UID
 101 in r8,spdr ; recieve in left channel lsb
 102 ;
 103 ; function end
 104 
 105 
 106 ; 2. reading from the sram - 16b
 107 ;
 108 ; this code will read a 16b value from the sram, using a 16b address.  this
 109 ; is faster than using the full 18b address space. the 16b address space
 110 ; is also convenient to use when difficult address calculations are
 111 ; required (i.e. youre doing more than just incrementing the address).
 112 
 113 ; register usage:
 114 ;
 115 ; r16 data lsb - can be any register
 116 ; r17 data msb - can be any register
 117 ; r18 swap register - must be one of r16 - r31
 118 ; r28 read address lsb - can be any register
 119 ; r29 read address msb  - can be any register
 120 
 121 ; code:
 122 ;
 123 ;setup sram for read - this can be omitted if your code already has these
 124 ;registers set appropriately elsewhere. if you are unsure, you should set
 125 ;them here, as you can severly damage your sram if its not setup
 126 ;correctly. you only need to to do this once for any consecutive reads.
 127 ;there are also other ways of accomplishing this task, but this is the
 128 ;easiest way.
 129 clr r18 ; prepare to set i/o to input for data read
 130 out ddra,r18 ; set porta as input for data read
 131 out ddrc,r18 ; set portc as input for data read
 132 ldi r18,$04
 133 out portg,r18 ; pull ce low, we high, and set high bits of register to b00
 134 
 135 ;read data from sram
 136 out portd,r28 ; set address lsb
 137 sts porth,r29 ; set address msb
 138 nop ; wait required microcontroller i/o setup time of 2 cycles
 139 nop ; can place other code here for efficient usage of time
 140 in r16,pina ; get data lsb
 141 in r17,pinc ; get data msb
 142 ;
 143 ; function done
 144 
 145 
 146 ; 3. reading from the sram - 18b
 147 ;
 148 ; this code will read a 16b value from the sram, using an 18b address.
 149 
 150 ; register usage:
 151 ;
 152 ; r16 data lsb - can be any register
 153 ; r17 data msb - can be any register
 154 ; r18 swap register - must be one of r16 - r31
 155 ; r23 read address high byte - can be any register
 156 ; r28 read address lsb - can be any register
 157 ; r29 read address msb  - can be any register
 158 
 159 ; code:
 160 ;
 161 ;setup sram for read - this can be omitted if your code already has these
 162 ;registers set appropriately elsewhere. if you are unsure, you should set
 163 ;them here, as you can severly damage your sram if its not setup
 164 ;correctly. you only need to to do this once for any consecutive reads.
 165 ;there are also other ways of accomplishing this task, but this is the
 166 ;easiest way.
 167 clr r18 ; prepare to set i/o to input for data read
 168 out ddra,r18 ; set porta as input for data read
 169 out ddrc,r18 ; set portc as input for data read
 170 ldi r18,$04 ; this line and the next can be omitted if the "out portg,r23"
 171 ; line directly follows "out ddrc,r18" from above.
 172 out portg,r18 ; pull ce low, we high, and set high bits of register to b00
 173 
 174 ;read data from sram
 175 out portg,r23 ; pull ce low, we high, and set high bits of register
 176 ; it is critical that r23 be of the format b000001dd where dd are the
 177 ; address high bits (i.e. only $04 - $07 are valid). damage to the sram
 178 ; can occur if this is not followed.
 179 out portd,r28 ; set address lsb
 180 sts porth,r29 ; set address msb
 181 nop ; wait required microcontroller i/o setup time of 2 cycles
 182 nop ; can place other code here for efficient usage of time
 183 in r16,pina ; get data lsb
 184 in r17,pinc ; get data msb
 185 ;
 186 ; function done
 187 
 188 
 189 ; 4. writing to the sram - 16b
 190 ;
 191 ; this code will write a 16b value to the sram, using a 16b address.  this
 192 ; is faster than using the full 18b address space. the 16b address space
 193 ; is also convenient to use when difficult address calculations are
 194 ; required (i.e. youre doing more than just incrementing the address).
 195 
 196 ; register usage:
 197 ;
 198 ; r16 data lsb - can be any register
 199 ; r17 data msb - can be any register
 200 ; r18 swap register - can be any register
 201 ; r19 swap register - must be one of r16 - r31
 202 ; r24 write address lsb - can be any register
 203 ; r25 write address msb  - can be any register
 204 
 205 ; code:
 206 ;
 207 ; this is not the most efficient method of writing to the sram if you
 208 ; are doing many consecutive writes, but is more efficient for 
 209 ; consecutive reads, as it leaves the sram in the read state, and assumes
 210 ; it is in the read state to begin with.  check the sram datasheet for
 211 ; other write modes for your application if speed is critical.
 212 ;
 213 ;setup sram - can be omitted if already setup, or if previous operation
 214 ;was a read as shown above.
 215 clr r18 ; prepare to set i/o to input for data read
 216 out ddra,r18 ; set porta as input for data read
 217 out ddrc,r18 ; set portc as input for data read
 218 ldi r19,$04
 219 out portg,r19 ; pull ce low, we high, and set high bits of register to b00
 220 
 221 ;sram write
 222 clr r18 ; prepare for sram setting and microcontroller i/o setting - can be
 223 ; omitted if a register is set to zero (null register) elsewhere.
 224 out portd,r24 ; set address lsb
 225 sts porth,r25 ; set address msb
 226 out portg,r18 ; pull ce low,we low,and set high bits of address
 227 ldi r19,$ff
 228 out ddra,r19 ; set porta as output for data write
 229 out ddrc,r19 ; set portc as output for data write
 230 out porta,r16 ; set data lsb
 231 out portc,r17 ; set data msb
 232 sbi portg,portg2 ; pull we high to write
 233 out ddra,r18 ; set porta as input for data lines
 234 out ddrc,r18 ; set portc as input for data lines
 235 ;
 236 ; function end
 237 
 238 
 239 ; 5. writing to the sram - 18b
 240 ;
 241 ; this code will write a 16b value to the sram, using an 18b address.
 242 
 243 ; register usage:
 244 ;
 245 ; r16 data lsb - can be any register
 246 ; r17 data msb - can be any register
 247 ; r18 swap register - can be any register
 248 ; r19 swap register - must be one of r16 - r31
 249 ; r22 write address high byte -  can be any register
 250 ; r24 write address lsb - can be any register
 251 ; r25 write address msb  - can be any register
 252 
 253 ; code:
 254 ;
 255 ; this is not the most efficient method of writing to the sram if you
 256 ; are doing many consecutive writes, but is more efficient for 
 257 ; consecutive reads, as it leaves the sram in the read state, and assumes
 258 ; it is in the read state to begin with.  check the sram datasheet for
 259 ; other write modes for your application if speed is critical.
 260 ;
 261 ;setup sram - can be omitted if already setup, or if previous operation
 262 ;was a read as shown above.
 263 clr r18 ; prepare to set i/o to input for data read
 264 out ddra,r18 ; set porta as input for data read
 265 out ddrc,r18 ; set portc as input for data read
 266 ldi r19,$04
 267 out portg,r19 ; pull ce low, we high, and set high bits of register to b00
 268 
 269 ;sram write
 270 clr r18 ; prepare for microcontroller i/o setting - can be
 271 ; omitted if a register is set to zero (null register) elsewhere.
 272 out portd,r24 ; set address lsb
 273 sts porth,r25 ; set address msb
 274 out portg,r22 ; pull ce low, we low, and set high bits of register
 275 ; it is critical that r22 be of the format b000000dd where dd are the
 276 ; address high bits (i.e. only $00 - $03 are valid). damage to the sram
 277 ; can occur if this is not followed.
 278 ldi r19,$ff
 279 out ddra,r19 ; set porta as output for data write
 280 out ddrc,r19 ; set portc as output for data write
 281 out porta,r16 ; set data lsb
 282 out portc,r17 ; set data msb
 283 sbi portg,portg2 ; pull we high to write
 284 out ddra,r18 ; set porta as input for data lines
 285 out ddrc,r18 ; set portc as input for data lines
 286 ;
 287 ; function end
 288 
 289 
 290 ; 6. sampling the switch to change functions - no initialization
 291 ;
 292 ; this must be done in a consistent fashion so all subprograms work with the
 293 ; main loop. r31:r30 hold the jump vector, and must be reset at the end of
 294 ; any subprogram.  you can either not alter these register, store them on
 295 ; the stack, or recalculate them on each pass through the subprogram.  i
 296 ; usually leave them unaltered, as this consumes the least time.  the
 297 ; program shown here samples the switch once every 256 cycles.  this gives
 298 ; a little bit more glitch immunity (as the switch is not debounced in
 299 ; hardware), and keeps the microcontroller from starting every program it
 300 ; passes along the way between the first switch position and the last. this
 301 ; isnt required, but makes things a little nicer.
 302 
 303 ; register usage
 304 ;
 305 ; r15 switch sample counter - can be any register
 306 ; r17 temporary register - must be one of r16 - r31
 307 ; r31 jump location msb - must be r31
 308 
 309 ; code:
 310 ;
 311 ;this code assumes there is no initialization in the subprogram (i.e. the
 312 ;program starts at initial jump location), and that r30 is set to $00, and
 313 ;is not altered during the subprogram, ever.
 314 dec r15 ; downcount sample counter
 315 brne done_UID ; check switch every 256 cycles
 316 lds r31,pinj ; get switch data
 317 andi r31,$78 ; mask off rotary switch
 318 ldi r17,$02 ; prepare to adjust switch position to program memory location
 319 lsr r31
 320 lsr r31
 321 add r31,r17 ; adjust switch position to program memory location
 322 
 323 done_UID:
 324 
 325 reti ; i usually place the switch sampling at the end of my code, but other
 326 ; code can follow in place of the reti
 327 ;
 328 ; function end
 329 
 330 
 331 ; 7. sampling the switch to change functions - with initialization
 332 ;
 333 ; this must be done in a consistent fashion so all subprograms work with the
 334 ; main loop. r31:r30 hold the jump vector, and must be reset at the end of
 335 ; any subprogram.  you can either not alter these register, store them on
 336 ; the stack, or recalculate them on each pass through the subprogram.  i
 337 ; usually leave them unaltered, as this consumes the least time.  the
 338 ; program shown here samples the switch once every 256 cycles.  this gives
 339 ; a little bit more glitch immunity (as the switch is not debounced in
 340 ; hardware), and keeps the microcontroller from starting every program it
 341 ; passes along the way between the first switch position and the last. this
 342 ; isnt required, but makes things a little nicer.
 343 
 344 ; register usage
 345 ;
 346 ; r15 switch sample counter - can be any register
 347 ; r16 temporary register - must be one of r16 - r31
 348 ; r17 temporary register - must be one of r16 - r31
 349 ; r30 jump locatoin lsb - must be r30
 350 ; r31 jump location msb - must be r31
 351 
 352 ; code
 353 ;
 354 ;this code assumes that r30 is modified in the initialization routine (the
 355 ;routine at codespace corresponding to r30=$00), and that it is not modified
 356 ;in any way by the subprogram after that. 
 357 dec r15 ; downcount sample counter
 358 brne done_UID ; sample every 256 cycles
 359 lds r16,pinj ; get switch data to temporary register
 360 andi r16,$78 ; mask off rotary switch
 361 ldi r17,$02 ; prepare to adjust switch position
 362 lsr r16
 363 lsr r16
 364 add r16,r17 ; adjust switch position to program memory location
 365 cpse r16,r31 ; check if location has changed - dont reset r30 if it hasnt
 366 clr r30 ; reset jump location lsb to intial state ($00)
 367 mov r31,r16 ; set jump location msb to current swtich position
 368 
 369 done_UID:
 370 
 371 reti ; i usually place the switch sampling at the end of my code, but other
 372 ; code can follow in place of the reti
 373 ;
 374 ; function end
 375 
 376 
 377 ; 8. initialization routine
 378 ;
 379 ; this places a small set of code which is only run once when a subprogram
 380 ; is first called.  it adjusts the jump location accordingly.  this must be
 381 ; used with the switchsample routine which accounts for initialization. r30
 382 ; can not be modified anywhere in the subprogram.
 383 
 384 ; register usage:
 385 ;
 386 ; r30 jump location lsb - must be r30
 387 
 388 ; code:
 389 ;
 390 ;program starts here first time
 391 ;initialze z pointer for correct jump
 392 ;this assumes a less than 256 word jump
 393 ldi r30,$05 ; set jump location to program start - this constant must be
 394 ; calculated to coincide with the subsequent start location.  this can
 395 ; either be done by counting the instructions that follow, and noting
 396 ; their memory usage (as given in the instruction set), or by assembling
 397 ; the file and looking at the result in the disassembler (avrstudio has a
 398 ; a nice disassembler that you can quickly look at to find the right value).
 399 nop ; place your initialization routine here instead of the nops
 400 nop
 401 nop
 402 reti ; return and wait for next interrupt
 403 ;
 404 ; function end
 405 
 406 
 407 ; 9. 16b signed x 16b signed to (16b or 32b) signed number
 408 ;
 409 ; this is a simple multiplaction routine for 16b signed numbers that
 410 ; returns a 32b number, of which you can use the upper 16b if thats all
 411 ; that is required. multiplicands start out in r11:r10 and r9:r8, and the
 412 ; result ends up in r5:r4:r3:r2. you can use whichever starting or ending
 413 ; registers you wish.
 414 
 415 ; register usage
 416 ;
 417 ; r0  = multiply interim result lsb - must be this register
 418 ; r1  = multiply interim result msb - must be this register
 419 ; r2  = multiply final result lsb - can be any register
 420 ; r3  = multiply final resutl mlb - can be any register
 421 ; r4  = multiply final result mhb - can be any register
 422 ; r5  = multiply final result msb - can be any register
 423 ; r18 = multiplicand A lsb - must be one of register r16 - r23
 424 ; r19 = multiplicand A msb - must be one of register r16 - r23
 425 ; r20 = multiplicand B lsb - must be one of register r16 - r23
 426 ; r21 = multiplicand B msb - must be one of register r16 - r23
 427 ; r22 = null register - can be any register
 428 
 429 ; code
 430 ;
 431 clr r22 ; clear null register for carry addition/subtraction - not needed
 432 ; if already done elsewhere in the code
 433 movw r19:r18,r9:r8 ; move values to multiply register - not necessary if
 434 ; your values are already in those registers
 435 movw r21:r20,r11:r10 ; move values to multiply register - not necessary if
 436 ; your values are already in those registers
 437 muls r19,r21 ; (signed)Ah * (signed)Bh - multiply high bytes
 438 movw r5:r4,r1:r0 ; store high bytes result for later
 439 mul	r18,r20	; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 440 movw r3:r2,r1:r0 ; store low byets for later
 441 mulsu r19,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 442 sbc	r5,r22 ; r22 is cleared above - subtract sign bit
 443 add	r3,r0 ; accumulate result
 444 adc	r4,r1
 445 adc	r5,r22 ; r22 is cleared above
 446 mulsu r21,r18 ; (signed)Bh * (unsigned)Al - multiply middle bytes
 447 sbc	r5,r22 ; r22 is cleared above - subtract sign bit
 448 add	r3,r0 ; accumulate result
 449 adc	r4,r1
 450 adc	r5,r22 ; r22 is cleared above
 451 ;
 452 ; function end
 453 
 454 
 455 ; 9. 16b signed x 8b unsigned to (16b or 24b) signed number
 456 ;
 457 ; this is a simple multiplaction routine for 16b signed numbers that
 458 ; returns a 24b number, of which you can use the upper 16b if thats all
 459 ; that is required. multiplicands start out in r11:r10 and r9, and the
 460 ; result ends up in r5:r4:r3. you can use whichever starting or ending
 461 ; registers you wish.
 462 
 463 ; register usage
 464 ;
 465 ; r0  = multiply interim result lsb - must be this register
 466 ; r1  = multiply interim result msb - must be this register
 467 ; r3  = multiply final result fractional byte - can be any register
 468 ; r4  = multiply final result lsb - can be any register
 469 ; r5  = multiply final result msb - can be any register
 470 ; r18 = multiplicand A lsb - can be any register
 471 ; r19 = multiplicand A msb - must be one of register r16 - r23
 472 ; r21 = multiplicand B - must be one of register r16 - r23
 473 ; r22 = null register - can be any register
 474 
 475 ; code
 476 ;
 477 clr r22 ; clear null register for carry addition/subtraction - not needed
 478 ; if already done elsewhere in the code
 479 mov r21,r9 ; move value to multiply register - not necessary if
 480 ; your values are already in those registers
 481 movw r19:r18,r11:r10 ; move values to multiply register - not necessary if
 482 ; your values are already in those registers
 483 mulsu r19,r21 ; (signed)Ah * (unsigned)B - multiply high byte
 484 movw r5:r4,r1:r0 ; store result
 485 mul r18,r21 ; (unsigned)Al * (unsigned)B - multiply low byte
 486 mov r3,r0 ; store fractional byte - not needed for 16b result
 487 add r4,r1 ; accumulate result
 488 adc r5,r22 ; r22 is cleared above
 489 ;
 490 ; function end
 491 
 492 
 493 ; 10. 16b signed x 16b unsigned to (16b or 32b) signed number
 494 ;
 495 ; this is a simple multiplaction routine for 16b signed/unsigned numbers
 496 ; that returns a 32b number, of which you can use the upper 16b if thats all
 497 ; that is required. multiplicands start out in r11:r10 and r9:r8, and the
 498 ; result ends up in r5:r4:r3:r2. you can use whichever starting or ending
 499 ; registers you wish.
 500 
 501 ; register usage
 502 ;
 503 ; r0  = multiply interim result lsb - must be this register
 504 ; r1  = multiply interim result msb - must be this register
 505 ; r2  = multiply final result lsb - can be any register
 506 ; r3  = multiply final resutl mlb - can be any register
 507 ; r4  = multiply final result mhb - can be any register
 508 ; r5  = multiply final result msb - can be any register
 509 ; r18 = multiplicand A lsb - can be any register
 510 ; r19 = multiplicand A msb - must be one of register r16 - r23
 511 ; r20 = multiplicand B lsb - must be one of register r16 - r23
 512 ; r21 = multiplicand B msb - must be one of register r16 - r23
 513 ; r22 = null register - can be any register
 514 
 515 ; code
 516 ;
 517 clr r22 ; clear null register for carry addition/subtraction - not needed
 518 ; if already done elsewhere in the code
 519 movw r19:r18,r9:r8 ; move values to multiply register - not necessary if
 520 ; your values are already in those registers
 521 movw r21:r20,r11:r10 ; move values to multiply register - not necessary if
 522 ; your values are already in those registers
 523 mulsu r19,r21 ; (signed)Ah * (unsigned)Bh - multiply high bytes
 524 movw r5:r4,r1:r0 ; store high bytes result for later
 525 mul	r18,r20	; (unsigned)Al * (unsigned)Bl ; multiply low bytes
 526 movw r3:r2,r1:r0 ; store low byets for later
 527 mulsu r19,r20 ; (signed)Ah * (unsigned)Bl - multiply middle bytes
 528 sbc	r5,r22 ; r22 is cleared above - subtract sign bit
 529 add	r3,r0 ; accumulate result
 530 adc	r4,r1
 531 adc	r5,r22 ; r22 is cleared above
 532 mul r21,r18 ; (unsigned)Bh * (unsigned)Al - multiply middle bytes
 533 add	r3,r0 ; accumulate result
 534 adc	r4,r1
 535 adc	r5,r22 ; r22 is cleared above
 536 ;
 537 ; function end
 538 
 539 
 540 ; 11. two's complement of 16b number
 541 ;
 542 ; this function will give you the negative value of a signed number. i.e.
 543 ; positive values will become negative, and negative values will become
 544 ; positive.  it is good for 16b numbers. value $8000 (-32768) stays the same
 545 ; as there is no positive value that large (be careful of this if trying to
 546 ; take the absolute value of a number).  this function also gives you the
 547 ; complementary distance from a value to $0000, i.e. $0000 - r5:r4.
 548 
 549 ; register usage
 550 ;
 551 ; r4  = lsb - can be any register
 552 ; r5  = msb - can be any register
 553 ; r16 = temporary register - can be any register
 554 
 555 ; code
 556 ;
 557 clr r16 ; not required if a register already has value $00
 558 neg r4 ; invert
 559 adc r5,r16
 560 neg r5
 561 ;
 562 ; end function
 563 
 564 
 565 ; 12. two's complement of 24b number
 566 ;
 567 ; this function will give you the negative value of a signed number. i.e.
 568 ; positive values will become negative, and negative values will become
 569 ; positive.  it is good for 24b numbers. value starts in r5:r4:r3, and gets
 570 ; modified, and remains in those registers. value $800000 (-8388608 decimal),
 571 ; stays the same value, as there is no positive value that large (be careful
 572 ; of this if trying to take the absolute value of a number).  this function
 573 ; also gives you the complementary distance from a value to $000000, i.e.
 574 ; $000000 - r5:r4:r3.
 575 
 576 ; register usage
 577 ;
 578 ; r3  = fractional byte - can be any register
 579 ; r4  = lsb - can be any register
 580 ; r5  = msb - can be any register
 581 ; r16 = temporary register - must be one of r16 - r31
 582 ; r17 = temporary register - can be any register
 583 
 584 ; code
 585 ;
 586 ldi r16,$01 ; does not need to be done if a register already has value $01
 587 clr r17 ; does not need to be done if a register already has value $00
 588 com r3 ; invert value
 589 com r4
 590 com r5
 591 add r3,r16 ; r16 set to $01 above
 592 adc r4,r17 ; r17 cleared above
 593 adc r5,r17
 594 ;
 595 ; end function
 596 
 597 
 598 ; 14. adding signed numbers of different lengths
 599 ;
 600 ; this function adds signed number of different byte lengths, where the
 601 ; shorter length number represents a fraction of the higher length number.
 602 ; this is useful for accumulation, where 8b or 16b numbers will need to be
 603 ; added to 24b or 32b accumulation registers.  converting your number to an
 604 ; unsigned integer before accumulation is a workaround for not having to do
 605 ; this.
 606 
 607 ; register usage
 608 ;
 609 ; r0  = value 1 lsb - can be any register
 610 ; r1  = value 1 msb - can be any register
 611 ; r2  = value 2 lsb - can be any register
 612 ; r3  = value 2 mlb - can be any register
 613 ; r4  = value 2 mhb - can be any register
 614 ; r5  = value 2 msb - can be any register
 615 ; r16 = null register - can be any register
 616 
 617 ; code
 618 ;
 619 clr r16 ; does not need to be done if already cleared
 620 add r2,r0 ; begin accumulation
 621 adc r3,r1
 622 sbrc r1,$07 ; check if r1:r0 is negative
 623 dec r16 ; set null register to $ff if its negative (ldi r16,$ff could be
 624 ; used here as well, but requires a register of r16 -> r31)
 625 adc r4,r16 ; add in rest of carry bits
 626 adc r5,r16
 627 clr r16 ; reset null register - does not need to be done if later code does
 628 ; not assume a null register
 629 ;
 630 ; end function
 631 

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.

You are not allowed to attach a file to this page.