1/* Intel SIMD SSE2 implementation of Viterbi ACS butterflies 2 for 256-state (k=9) convolutional code 3 Copyright 2004 Phil Karn, KA9Q 4 This code may be used under the terms of the GNU Lesser General Public License (LGPL) 5 6 void update_viterbi29_blk_sse2(struct v29 *vp,unsigned char *syms,int nbits) ; 7*/ 8 9 # SSE2 (128-bit integer SIMD) version 10 # Requires Pentium 4 or better 11 # These are offsets into struct v29, defined in viterbi29.h 12 .set DP,512 13 .set OLDMETRICS,516 14 .set NEWMETRICS,520 15 16 .text 17 .global update_viterbi29_blk_sse2,Branchtab29_sse2 18 .type update_viterbi29_blk_sse2,@function 19 .align 16 20 21update_viterbi29_blk_sse2: 22 pushl %ebp 23 movl %esp,%ebp 24 pushl %esi 25 pushl %edi 26 pushl %edx 27 pushl %ebx 28 29 movl 8(%ebp),%edx # edx = vp 30 testl %edx,%edx 31 jnz 0f 32 movl -1,%eax 33 jmp err 340: movl OLDMETRICS(%edx),%esi # esi -> old metrics 35 movl NEWMETRICS(%edx),%edi # edi -> new metrics 36 movl DP(%edx),%edx # edx -> decisions 37 381: movl 16(%ebp),%eax # eax = nbits 39 decl %eax 40 jl 2f # passed zero, we're done 41 movl %eax,16(%ebp) 42 43 xorl %eax,%eax 44 movl 12(%ebp),%ebx # ebx = syms 45 movb (%ebx),%al 46 movd %eax,%xmm6 # xmm6[0] = first symbol 47 movb 1(%ebx),%al 48 movd %eax,%xmm5 # xmm5[0] = second symbol 49 addl $2,%ebx 50 movl %ebx,12(%ebp) 51 52 punpcklbw %xmm6,%xmm6 # xmm6[1] = xmm6[0] 53 punpcklbw %xmm5,%xmm5 54 movdqa thirtyones,%xmm7 55 pshuflw $0,%xmm6,%xmm6 # copy low word to low 3 56 pshuflw $0,%xmm5,%xmm5 57 punpcklqdq %xmm6,%xmm6 # propagate to all 16 58 punpcklqdq %xmm5,%xmm5 59 # xmm6 now contains first symbol in each byte, xmm5 the second 60 61 movdqa thirtyones,%xmm7 62 63 # each invocation of this macro does 16 butterflies in parallel 64 .MACRO butterfly GROUP 65 # compute branch metrics 66 movdqa Branchtab29_sse2+(16*\GROUP),%xmm4 67 movdqa Branchtab29_sse2+128+(16*\GROUP),%xmm3 68 pxor %xmm6,%xmm4 69 pxor %xmm5,%xmm3 70 pavgb %xmm3,%xmm4 71 psrlw $3,%xmm4 72 73 pand %xmm7,%xmm4 # xmm4 contains branch metrics 74 75 movdqa (16*\GROUP)(%esi),%xmm0 # Incoming path metric, high bit = 0 76 movdqa ((16*\GROUP)+128)(%esi),%xmm3 # Incoming path metric, high bit = 1 77 movdqa %xmm0,%xmm2 78 movdqa %xmm3,%xmm1 79 paddusb %xmm4,%xmm0 80 paddusb %xmm4,%xmm3 81 82 # invert branch metrics 83 pxor %xmm7,%xmm4 84 85 paddusb %xmm4,%xmm1 86 paddusb %xmm4,%xmm2 87 88 # Find survivors, leave in mm0,2 89 pminub %xmm1,%xmm0 90 pminub %xmm3,%xmm2 91 # get decisions, leave in mm1,3 92 pcmpeqb %xmm0,%xmm1 93 pcmpeqb %xmm2,%xmm3 94 95 # interleave and store new branch metrics in mm0,2 96 movdqa %xmm0,%xmm4 97 punpckhbw %xmm2,%xmm0 # interleave second 16 new metrics 98 punpcklbw %xmm2,%xmm4 # interleave first 16 new metrics 99 movdqa %xmm0,(32*\GROUP+16)(%edi) 100 movdqa %xmm4,(32*\GROUP)(%edi) 101 102 # interleave decisions & store 103 movdqa %xmm1,%xmm4 104 punpckhbw %xmm3,%xmm1 105 punpcklbw %xmm3,%xmm4 106 # work around bug in gas due to Intel doc error 107 .byte 0x66,0x0f,0xd7,0xd9 # pmovmskb %xmm1,%ebx 108 shll $16,%ebx 109 .byte 0x66,0x0f,0xd7,0xc4 # pmovmskb %xmm4,%eax 110 orl %eax,%ebx 111 movl %ebx,(4*\GROUP)(%edx) 112 .endm 113 114 # invoke macro 8 times for a total of 128 butterflies 115 butterfly GROUP=0 116 butterfly GROUP=1 117 butterfly GROUP=2 118 butterfly GROUP=3 119 butterfly GROUP=4 120 butterfly GROUP=5 121 butterfly GROUP=6 122 butterfly GROUP=7 123 124 addl $32,%edx # bump decision pointer 125 126 # see if we have to normalize 127 movl (%edi),%eax # extract first output metric 128 andl $255,%eax 129 cmp $50,%eax # is it greater than 50? 130 movl $0,%eax 131 jle done # No, no need to normalize 132 133 # Normalize by finding smallest metric and subtracting it 134 # from all metrics 135 movdqa (%edi),%xmm0 136 pminub 16(%edi),%xmm0 137 pminub 32(%edi),%xmm0 138 pminub 48(%edi),%xmm0 139 pminub 64(%edi),%xmm0 140 pminub 80(%edi),%xmm0 141 pminub 96(%edi),%xmm0 142 pminub 112(%edi),%xmm0 143 pminub 128(%edi),%xmm0 144 pminub 144(%edi),%xmm0 145 pminub 160(%edi),%xmm0 146 pminub 176(%edi),%xmm0 147 pminub 192(%edi),%xmm0 148 pminub 208(%edi),%xmm0 149 pminub 224(%edi),%xmm0 150 pminub 240(%edi),%xmm0 151 152 # crunch down to single lowest metric 153 movdqa %xmm0,%xmm1 154 psrldq $8,%xmm0 # the count to psrldq is bytes, not bits! 155 pminub %xmm1,%xmm0 156 movdqa %xmm0,%xmm1 157 psrlq $32,%xmm0 158 pminub %xmm1,%xmm0 159 movdqa %xmm0,%xmm1 160 psrlq $16,%xmm0 161 pminub %xmm1,%xmm0 162 movdqa %xmm0,%xmm1 163 psrlq $8,%xmm0 164 pminub %xmm1,%xmm0 165 166 punpcklbw %xmm0,%xmm0 # lowest 2 bytes 167 pshuflw $0,%xmm0,%xmm0 # lowest 8 bytes 168 punpcklqdq %xmm0,%xmm0 # all 16 bytes 169 170 # xmm0 now contains lowest metric in all 16 bytes 171 # subtract it from every output metric 172 movdqa (%edi),%xmm1 173 psubusb %xmm0,%xmm1 174 movdqa %xmm1,(%edi) 175 movdqa 16(%edi),%xmm1 176 psubusb %xmm0,%xmm1 177 movdqa %xmm1,16(%edi) 178 movdqa 32(%edi),%xmm1 179 psubusb %xmm0,%xmm1 180 movdqa %xmm1,32(%edi) 181 movdqa 48(%edi),%xmm1 182 psubusb %xmm0,%xmm1 183 movdqa %xmm1,48(%edi) 184 movdqa 64(%edi),%xmm1 185 psubusb %xmm0,%xmm1 186 movdqa %xmm1,64(%edi) 187 movdqa 80(%edi),%xmm1 188 psubusb %xmm0,%xmm1 189 movdqa %xmm1,80(%edi) 190 movdqa 96(%edi),%xmm1 191 psubusb %xmm0,%xmm1 192 movdqa %xmm1,96(%edi) 193 movdqa 112(%edi),%xmm1 194 psubusb %xmm0,%xmm1 195 movdqa %xmm1,112(%edi) 196 movdqa 128(%edi),%xmm1 197 psubusb %xmm0,%xmm1 198 movdqa %xmm1,128(%edi) 199 movdqa 144(%edi),%xmm1 200 psubusb %xmm0,%xmm1 201 movdqa %xmm1,144(%edi) 202 movdqa 160(%edi),%xmm1 203 psubusb %xmm0,%xmm1 204 movdqa %xmm1,160(%edi) 205 movdqa 176(%edi),%xmm1 206 psubusb %xmm0,%xmm1 207 movdqa %xmm1,176(%edi) 208 movdqa 192(%edi),%xmm1 209 psubusb %xmm0,%xmm1 210 movdqa %xmm1,192(%edi) 211 movdqa 208(%edi),%xmm1 212 psubusb %xmm0,%xmm1 213 movdqa %xmm1,208(%edi) 214 movdqa 224(%edi),%xmm1 215 psubusb %xmm0,%xmm1 216 movdqa %xmm1,224(%edi) 217 movdqa 240(%edi),%xmm1 218 psubusb %xmm0,%xmm1 219 movdqa %xmm1,240(%edi) 220 221done: 222 # swap metrics 223 movl %esi,%eax 224 movl %edi,%esi 225 movl %eax,%edi 226 jmp 1b 227 2282: movl 8(%ebp),%ebx # ebx = vp 229 # stash metric pointers 230 movl %esi,OLDMETRICS(%ebx) 231 movl %edi,NEWMETRICS(%ebx) 232 movl %edx,DP(%ebx) # stash incremented value of vp->dp 233 xorl %eax,%eax 234err: popl %ebx 235 popl %edx 236 popl %edi 237 popl %esi 238 popl %ebp 239 ret 240 241 .data 242 .align 16 243thirtyones: 244 .byte 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31 245 246