📄 bitmanm.h
字号:
;/*
; * Bit Manipulation assembler
; * Copyright (C) ARM Limited 1998-1999. All rights reserved.
; */
;---------------------------------------------------------------
; Generally Useful Code Fragments
;
;---------------------------------------------------------------
; Each code fragment is implemented in the form of a MACRO so
; that it can be inlined.
;
; Contents:
;
; binary coded decimal (BCD) addition
; BCDADD
; bit reversal in a word
; BITREV, BITREVC
; byte reversal in a word
; BYTEREV, BYTEREVC
; bytewise maximum
; BYTEWISEMAX
; least and most significant bit set
; LSBSET, MSBSET
; population count (1's in binary representation of integer)
; POPCOUNT, POPCOUNT7 (over seven words)
;
;---------------------------------------------------------------
INCLUDE regchekm.h
;---------------------------------------------------------------
; Binary Coded Decimal (BCD) Addition
; 7 cycles
;
;---------------------------------------------------------------
; $a binary coded decimal input a
; $b binary coded decimal input b
; $c output result of binary coded decimal addition
; $t temporary register
;
; constant1 = 0x33333333
; constant2 = 0x88888888
;
; the code returns in c the binary coded decimal addition of
; a + b (or a + b + carry if code adjusted accordingly)
; where a and b are valid BCD numbers - i.e. every nibble
; lies in the range 0-9 (else the result will be meaningless)
;
; Registers $constant1 and $constant2 must be distinct from each other.
; Register $t must be a distinct register from each of $a, $b, $c
; and $constant2.
; Register $c must be a distinct register from both $a and $b.
; Registers $a and $b need not be distinct from each other.
; Register $constant1 need not be distinct from $a, $b, $c or $t
; Register $constant2 need not be distinct from $a, $b or $c
;
;---------------------------------------------------------------
MACRO
BCDADD $c, $a, $b, $t, $constant1, $constant2, $withcarry
DISTINCT $constant1, $constant2
DISTINCT $a, $c, $t
DISTINCT $b, $c, $t
DISTINCT $constant2, $t
;Suppose we add a, b and 0x66666666. Look at the least significant nibble
;("LSN") of this sum. This will generate a carry into the next nibble if:
;
;LSN(a) + LSN(b) + 6 >= 16,
;
;i.e. if:
;
;LSN(a) + LSN(b) >= 10.
;
;Which is precisely the condition we want for whether the LSN of the BCD
;sum generates a carry into the next nibble.
;
;Looking at the next nibble, we then find that it generates a carry into
;the third nibble if:
;
;NextNybble(a) + NextNybble(b) + (Carry from LSN) + 6 >= 16,
;
;i.e. if:
;
;NextNybble(a) + NextNybble(b) + (Carry from LSN) >= 10,
;
;which is precisely when we want this nibble to generate a carry into the
;third nibble in the BCD sum. This clearly continues all the way through,
;so the carries between nibbles in the a+b+0x66666666 addition are
;precisely those we want between the BCD digits.
ADDS $c,$a,$b ;start BCD equivalent of ADD $c, $a, $b
;but corrupts the flags else...
;ADCS $c, $a, $b ;...use this line instead to perform the BCD
;equivalent of ADC $c, $a, $b which adds
;the carry flag as well
ADD $t,$constant1,$c,RRX ;Generate sum with BCD carries
EOR $t,$t,$a,LSR #1 ; )
EOR $t,$t,$b,LSR #1 ; ) Isolate those carries
AND $t,$t,$constant2 ; )
ADD $c,$c,$t,LSR #1 ;Adjust sum according to the BCD
ADD $c,$c,$t,LSR #2 ; carries
;After the first instruction, c contains the 33 bit unsigned sum of a
;and b. So the RRX shift in the second instruction ends up generating the
;true unsigned version of (a+b) >> 1, and the addition of 0x33333333 then
;gives us (a+b+0x66666666) >> 1. So to get the carries out of each of the
;nibbles of the BCD sum, we want the carries into bits 3, 7, 11, 15, 19,
;23, 27 and 31 of the result of the second instruction. (Note that although
;three operands have been added together, there can only be a single carry
;out of any nibble, because the operand nibbles are all 0-9 and the third
;nibble is effectively 6.)
;
;To get the carry into a bit of a sum which is known to have only had a
;single carry into it, you can use the fact that:
;
;(sum bit) = (EOR of all the operand bits) EOR (carry in bit),
;
;or equivalently:
;
;(carry in bit) = (EOR of all the operand bits) EOR (sum bit)
;
;Since the relevant bits of the constant 0x33333333 are all zero, we can
;EOR with a >> 1 and b >> 1 to get a value in which bits 3, 7, 11, 15,
;19, 23, 27 and 31 are the desired BCD carries out of each nibble. Then
;ANDing with 0x88888888 will isolate those carries.
;Now all we have to do is add 6 to each nibble of the original sum of a
;and b which should have produced a BCD carry out, to force its value to
;the correct BCD digit and to force it to produce a carry into the next
;nibble if it hasn't already.
;
;Note that the carry out from the top nibble of the BCD addition is
;in bit 31 of $t so the code might be adjusted to move this into the
;carry flag which would allow the synthesis of multi-precision BCD
;additions
MEND
;---------------------------------------------------------------
; Reverse the required bit-size units
; 3 cycles + 1 register constant
;
;---------------------------------------------------------------
; $a input word
; $c output result of unit reversal
; $t temporary register
; $constant temporary register containing one of the following
; according to the unit bit size
; 0x0000FFFF reverse units of 16-bits (2 bytes)
; 0x00FF00FF reverse units of 8-bits (1 byte)
; 0x0F0F0F0F reverse units of 4-bits (1 nibble)
; 0x33333333 reverse units of 2-bits
; 0x55555555 reverse units of 1-bit
; $bits one of 16, 8, 4, 2 or 1 according to unit bit size
; another other value (including 32) returns $a in $c
;
; Register $t must be distinct from registers $a, $c and $constant
; Registers $constant, $a and $c need not be distinct from each other
;
;---------------------------------------------------------------
MACRO
REVERSEUNITS $c, $a, $t, $constant, $bits
DISTINCT $t, $constant
DISTINCT $t, $a
DISTINCT $t, $c
IF $bits = 16 :LOR: $bits = 8 :LOR: $bits = 4 :LOR: $bits = 2 :LOR: $bits = 1
AND $t, $constant, $a, LSR #$bits
AND $c, $a, $constant
ORR $c, $t, $c, LSL #$bits ; reversed units of $bits bits
ELSE
MOV $c, $a
ENDIF
MEND
;---------------------------------------------------------------
; Bit reversal within a word
; 17 cycles or 12 cycles/value + 5 setup cycles
;
;---------------------------------------------------------------
; $a input word
; $c output result of bit reversal
; $t temporary register
; $constant temporary register to hold constants (BITREV only)
;
; constant1 = 0xFFFF00FF (BITREVC only)
; constant2 = 0x0F0F0F0F (BITREVC only)
; constant3 = 0x33333333 (BITREVC only)
; constant4 = 0x55555555 (BITREVC only)
;
; reverses a and places the answer in c supposing each bit x of a
; is reversed to be in bit 31-x (bits 0 to 31)
;
; first method takes 12 cycles but needs 4 register constants set
; prior to the macro call and thus five temporary registers
;
; the second method takes 17 cycles but does not need a register
; set up, and so only requires two temporary registers
;
;---------------------------------------------------------------
;---------------------------------------------------------------
; Bit reversal within a word - method 1
; 17 cycles
;
; $a input word
; $c output result of byte reversal
; $t temporary register
; $constant temporary register (to hold constants during reversal)
;
; Registers $t and $constant must be distinct from each other
; Registers $t and $constant must be distinct from both $a and $c
; Registers $a and $c need not be distinct from each other
;
;---------------------------------------------------------------
MACRO
BITREV $c, $a, $t, $constant
DISTINCT $constant, $a
DISTINCT $constant, $c
MVN $constant, #0xFF00 ; constant = 0xFFFF00FF
; use BYTEREVC since require constant for future constant construction
BYTEREVC $c, $a, $t, $constant ; endianness swap
BIC $constant, $constant, #0xFF000000
EOR $constant, $constant, $constant, LSL #4 ; $constant = 0x0F0F0F0F
REVERSEUNITS $c, $c, $t, $constant, 4
EOR $constant, $constant, $constant, LSL #2 ; $constant = 0x33333333
REVERSEUNITS $c, $c, $t, $constant, 2
EOR $constant, $constant, $constant, LSL #1 ; $constant = 0x55555555
REVERSEUNITS $c, $c, $t, $constant, 1
MEND
;---------------------------------------------------------------
; Bit reversal within a word - method 2
; 12 cycles/value + 4 register constants
;
; $a input word
; $c output result of bit reversal
; $t temporary register
;
; constant1 = 0xFFFF00FF
; constant2 = 0x0F0F0F0F
; constant3 = 0x33333333
; constant4 = 0x55555555
;
; Register $t must be distinct from registers $a, $c, $constant1,
; $constant2, $constant3 and $constant4
; Register $c must be distinct from registers $constant2, $constant3
; and $constant4
; Register $c need not be distinct from register $constant1 or $a
; Register $a need not be distinct from any of registers $constant1,
; $constant2, $constant3 or $constant4
;
;---------------------------------------------------------------
MACRO
BITREVC $c, $a, $t, $constant1, $constant2, $constant3, $constant4
DISTINCT $constant1, $constant2, $constant3, $constant4
DISTINCT $c, $constant2, $constant3, $constant4
BYTEREVC $c, $a, $t, $constant1 ; endianness swap
REVERSEUNITS $c, $c, $t, $constant2, 4
REVERSEUNITS $c, $c, $t, $constant3, 2
REVERSEUNITS $c, $c, $t, $constant4, 1
MEND
;---------------------------------------------------------------
; Byte reversal within a word
; 4 cycles or 3 cycles/value + 1 setup cycle
;
;---------------------------------------------------------------
; $a input word
; $c output result of byte reversal
; $t temporary register
;
; $constant = 0xFFFF00FF (BYTEREVC only)
;
; reverses a and places the answer in c supposing a=(a,b,c,d)
; in bytes (a=msb)
;
; first method takes 3 cycles but needs a register constant set
; prior to the macro call and thus two temporary registers
;
; the second method takes 4 cycles but does not need a register
; set up, and so only requires one temporary register
;
;---------------------------------------------------------------
;---------------------------------------------------------------
; Byte reversal within a word - method 1
; 4 cycles
;
; $a input word
; $c output result of byte reversal
; $t temporary register
;
; Both registers $a and $c must be distinct from register $t
; Register $c need not be distinct from $a.
;
;---------------------------------------------------------------
MACRO
BYTEREV $c, $a, $t
DISTINCT $t, $a
DISTINCT $t, $c
EOR $t, $a, $a, ROR#16 ; (a^c)(b^d)(a^c)(b^d)
BIC $t, $t, #0xFF0000 ; (a^c) 0 (a^c)(b^d)
MOV $c, $a, ROR #8 ; d a b c
EOR $c, $c, $t, LSR#8 ; d c b a
MEND
;---------------------------------------------------------------
; Byte reversal within a word - method 2
; 3 cycles/value + 1 register constant
;
; $a input word
; $c output result of byte reversal
; $t temporary register
;
; $constant = 0xFFFF00FF
;
; Both registers $a and $constant must be distinct from register $t
; Registers $a, $c and $constant need not be distinct from each other
; Registers $c and $t need not be distinct from each other
;
;---------------------------------------------------------------
MACRO
BYTEREVC $c, $a, $t, $constant
DISTINCT $t, $a
DISTINCT $t, $constant
EOR $t, $a, $a, ROR #16 ; (a^c)(b^d)(a^c)(b^d)
AND $t, $constant, $t, LSR#8 ; 0 (a^c) 0 (a^c)
EOR $c, $t, $a, ROR #8 ; d c b a
MEND
;---------------------------------------------------------------
; Bytewise maximum
; 8 cycles
;
;---------------------------------------------------------------
; $a input a
; $b input b
; $c each byte of output result
; = MAX( corresponding bytes of a and b)
; $d each byte of output result
; = 0 or 1 if corresponding byte of a or b chosen (respectively)
; $t temporary register
;
; constant = 0x01010101
;
; the code returns in each byte of c the maximum value of the corresponding
; byte from a or b and returns in each byte of d a 0 (zero) if the corresponding
; byte in c was chosen from a or a 1 (one) if the corresponding byte in c
; was chosen from b
;
; if the bytes of a and b are identical it is assumed it is unimportant which
; is selected and thus the corresponding byte of d may contain either a 0 or a 1
;
; all bytes are treated as unsigned
;
; Registers $a, $c, $d and $t must be distinct registers from each other
; Register $c must be distinct from $b
; Registers $c and $d must be distinct from $constant
; Either register $d or $t need not be distinct from register $b
; Register $t need not be distinct from register $constant
; Registers $a, $b and $constant need not be distinct from each other
;
;---------------------------------------------------------------
MACRO
BYTEWISEMAX $c, $d, $a, $b, $t, $constant
DISTINCT $a, $c, $d, $t
DISTINCT $b, $c
DISTINCT $c, $d, $constant
EOR $c,$a,$b ;EOR of operands used twice below
SUBS $d,$a,$b ;Do a 32-bit subtraction
EOR $d,$d,$c ;EOR with operands to generate
; borrows into each bit
AND $d,$constant,$d,LSR #8 ;Isolate borrows into bits 8, 16, 24
; and shift into bits 0, 8, 16
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -