r42: Moved from a plugin to a statically linked component of Cinelerra.
authorHerman Robak <herman@skolelinux.no>
Fri, 3 Oct 2003 23:44:05 +0000 (23:44 +0000)
committerHerman Robak <herman@skolelinux.no>
Fri, 3 Oct 2003 23:44:05 +0000 (23:44 +0000)
23 files changed:
mpeg2enc/attributes.h [new file with mode: 0644]
mpeg2enc/bdist1_mmx.s [new file with mode: 0644]
mpeg2enc/bdist2_mmx.s [new file with mode: 0644]
mpeg2enc/config.h [new file with mode: 0644]
mpeg2enc/cpu_accel.h [new file with mode: 0644]
mpeg2enc/dist2_mmx.s [new file with mode: 0644]
mpeg2enc/fastintfns.h [new file with mode: 0644]
mpeg2enc/fdct_mmx.s [new file with mode: 0644]
mpeg2enc/global.h [new file with mode: 0644]
mpeg2enc/idct_mmx.s [new file with mode: 0644]
mpeg2enc/mblock_sad_mmx.s [new file with mode: 0644]
mpeg2enc/mblock_sad_mmxe.s [new file with mode: 0644]
mpeg2enc/mblockq_sad_mmxe.s [new file with mode: 0644]
mpeg2enc/mmx.h [new file with mode: 0644]
mpeg2enc/mpeg2enc.h [new file with mode: 0644]
mpeg2enc/mtable.h [new file with mode: 0644]
mpeg2enc/predcomp_mmx.s [new file with mode: 0644]
mpeg2enc/predcomp_mmxe.s [new file with mode: 0644]
mpeg2enc/predict_mmx.s [new file with mode: 0644]
mpeg2enc/putbits.h [new file with mode: 0644]
mpeg2enc/quant_mmx.s [new file with mode: 0644]
mpeg2enc/simd.h [new file with mode: 0644]
mpeg2enc/vlc.h [new file with mode: 0644]

diff --git a/mpeg2enc/attributes.h b/mpeg2enc/attributes.h
new file mode 100644 (file)
index 0000000..8ed7aef
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * attributes.h
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ *
+ * mpeg2dec is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mpeg2dec is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+//use gcc attribs to align critical data structures
+#ifdef ATTRIBUTE_ALIGNED_MAX
+#define ATTR_ALIGN(align) __attribute__ ((__aligned__ ((ATTRIBUTE_ALIGNED_MAX < align) ? ATTRIBUTE_ALIGNED_MAX : align)))
+#else
+#define ATTR_ALIGN(align)
+#endif
diff --git a/mpeg2enc/bdist1_mmx.s b/mpeg2enc/bdist1_mmx.s
new file mode 100644 (file)
index 0000000..3460240
--- /dev/null
@@ -0,0 +1,329 @@
+;
+;  bdist1_mmx.s:  mmX optimized bidirectional absolute distance sum
+;
+;  Original believed to be Copyright (C) 2000 Brent Byeler
+;
+;  This program is free software; you can reaxstribute it and/or
+;  modify it under the terms of the GNU General Public License
+;  as published by the Free Software Foundation; either version 2
+;  of the License, or (at your option) any later version.
+;
+;  This program is distributed in the hope that it will be useful,
+;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;  GNU General Public License for more details.
+;
+;  You should have received a copy of the GNU General Public License
+;  along with this program; if not, write to the Free Software
+;  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+;
+
+;/*
+; * absolute difference error between a (16*h) block and a bidirectional
+; * prediction
+; *
+; * p2: address of top left pel of block
+; * pf,hxf,hyf: address and half pel flags of forward ref. block
+; * pb,hxb,hyb: address and half pel flags of backward ref. block
+; * h: height of block
+; * lx: distance (in bytes) of vertically adjacent pels in p2,pf,pb
+; * mmX version
+; */
+;int bdist1_mmx(
+;unsigned char *pf, unsigned char *pb, unsigned char *p2,
+;int lx, int hxf, int hyf, int hxb, int hyb, int h)
+;{
+;  unsigned char *pfa,*pfb,*pfc,*pba,*pbb,*pbc;
+
+; Handy macros for readbility
+
+%define pf [ebp+8]
+%define pb [ebp+12]
+%define p2 [ebp+16]
+%define lx [ebp+20]
+%define hxf [ebp+24]
+%define hyf [ebp+28]
+%define hxb [ebp+32]
+%define hyb [ebp+36]
+%define h   [ebp+40]
+
+
+%define pfa [esp+4]
+%define pfb [esp+8]
+%define pfc [esp+12]
+%define pba [esp+16]
+%define pbb [esp+20]
+%define pbc [esp+24]
+
+SECTION .text
+global bdist1_mmx
+
+align 32
+bdist1_mmx:
+       push ebp                        ; save frame pointer
+       mov ebp, esp            ; link
+       push ebx
+       push ecx
+       push edx
+       push esi     
+       push edi
+
+       ;;
+       ;; Make space for local variables on stack
+       sub       esp, 32
+
+
+       mov       edx, hxb
+       mov       eax, hxf
+       mov       esi, lx
+
+       mov       ecx, pf
+       add       ecx, eax
+       mov       pfa, ecx
+       mov       ecx, esi
+       imul      ecx, hyf
+       mov       ebx, pf
+       add       ecx, ebx
+       mov       pfb, ecx
+       add       eax, ecx
+       mov       pfc, eax
+       mov       eax, pb
+       add       eax, edx
+       mov       pba, eax
+       mov       eax, esi
+       imul      eax, hyb
+       mov       ecx, pb
+       add       eax, ecx
+       mov       pbb, eax
+       add       edx, eax
+       mov       pbc, edx
+       xor       esi, esi         ; esi is "s" the accumulator
+       mov       eax, esi
+
+       mov       edi, h
+       test      edi, edi  ; h = 0?
+       jle       near bdist1exit
+
+       pxor      mm7, mm7
+       pxor      mm6, mm6
+       pcmpeqw   mm5, mm5
+       psubw     mm6, mm5
+       psllw     mm6, 1
+
+bdist1top:
+       mov       eax, pf
+       mov       ebx, pfa
+       mov       ecx, pfb
+       mov       edx, pfc
+       movq      mm0, [eax]
+       movq      mm1, mm0
+       punpcklbw mm0, mm7
+       punpckhbw mm1, mm7
+       movq      mm2, [ebx]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       movq      mm2, [ecx]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       movq      mm2, [edx]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       paddw     mm0, mm6
+       paddw     mm1, mm6
+       psrlw     mm0, 2
+       psrlw     mm1, 2
+       mov       eax, pb
+       mov       ebx, pba
+       mov       ecx, pbb
+       mov       edx, pbc
+       movq      mm2, [eax]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       movq      mm4, [ebx]
+       movq      mm5, mm4
+       punpcklbw mm4, mm7
+       punpckhbw mm5, mm7
+       paddw     mm2, mm4
+       paddw     mm3, mm5
+       movq      mm4, [ecx]
+       movq      mm5, mm4
+       punpcklbw mm4, mm7
+       punpckhbw mm5, mm7
+       paddw     mm2, mm4
+       paddw     mm3, mm5
+       movq      mm4, [edx]
+       movq      mm5, mm4
+       punpcklbw mm4, mm7
+       punpckhbw mm5, mm7
+       paddw     mm2, mm4
+       paddw     mm3, mm5
+       paddw     mm2, mm6
+       paddw     mm3, mm6
+       psrlw     mm2, 2
+       psrlw     mm3, 2
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       psrlw     mm6, 1
+       paddw     mm0, mm6
+       paddw     mm1, mm6
+       psllw     mm6, 1
+       psrlw     mm0, 1
+       psrlw     mm1, 1
+       packuswb  mm0, mm1
+
+       mov       eax, p2
+       movq      mm1, [eax]
+       movq      mm2, mm0
+       psubusb   mm0, mm1
+       psubusb   mm1, mm2
+       por       mm0, mm1
+       movq      mm1, mm0
+       punpcklbw mm0, mm7
+       punpckhbw mm1, mm7
+       paddw     mm0, mm1
+       movq      mm1, mm0
+       punpcklwd mm0, mm7
+       punpckhwd mm1, mm7
+
+       paddd     mm0, mm1
+       movd      eax, mm0
+       psrlq     mm0, 32
+       movd      ebx, mm0
+       add       esi, eax
+       add       esi, ebx
+       mov       eax, pf
+       mov       ebx, pfa
+       mov       ecx, pfb
+       mov       edx, pfc
+       movq      mm0, [eax+8]
+       movq      mm1, mm0
+       punpcklbw mm0, mm7
+       punpckhbw mm1, mm7
+       movq      mm2, [ebx+8]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       movq      mm2, [ecx+8]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       movq      mm2, [edx+8]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       paddw     mm0, mm6
+       paddw     mm1, mm6
+       psrlw     mm0, 2
+       psrlw     mm1, 2
+       mov       eax, pb
+       mov       ebx, pba
+       mov       ecx, pbb
+       mov       edx, pbc
+       movq      mm2, [eax+8]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       movq      mm4, [ebx+8]
+       movq      mm5, mm4
+       punpcklbw mm4, mm7
+       punpckhbw mm5, mm7
+       paddw     mm2, mm4
+       paddw     mm3, mm5
+       movq      mm4, [ecx+8]
+       movq      mm5, mm4
+       punpcklbw mm4, mm7
+       punpckhbw mm5, mm7
+       paddw     mm2, mm4
+       paddw     mm3, mm5
+       movq      mm4, [edx+8]
+       movq      mm5, mm4
+       punpcklbw mm4, mm7
+       punpckhbw mm5, mm7
+       paddw     mm2, mm4
+       paddw     mm3, mm5
+       paddw     mm2, mm6
+       paddw     mm3, mm6
+       psrlw     mm2, 2
+       psrlw     mm3, 2
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       psrlw     mm6, 1
+       paddW     mm0, mm6
+       paddw     mm1, mm6
+       psllw     mm6, 1
+       psrlw     mm0, 1
+       psrlw     mm1, 1
+       packuswb  mm0, mm1
+       mov       eax, p2
+       movq      mm1, [eax+8]
+       movq      mm2, mm0
+       psubusb   mm0, mm1
+       psubusb   mm1, mm2
+       por       mm0, mm1
+       movq      mm1, mm0
+       punpcklbw mm0, mm7
+       punpckhbw mm1, mm7
+       paddw     mm0, mm1
+       movq      mm1, mm0
+       punpcklwd mm0, mm7
+       punpckhwd mm1, mm7
+       paddd     mm0, mm1
+       movd      eax, mm0
+       psrlq     mm0, 32
+       movd      ebx, mm0
+       add       esi, eax
+       add       esi, ebx
+
+    mov       eax, lx
+       add       p2, eax
+       add       pf, eax
+       add       pfa, eax
+       add       pfb, eax
+       add       pfc, eax
+       add       pb, eax
+       add       pba, eax
+       add       pbb, eax
+       add       pbc, eax
+
+       dec       edi
+       jg        near bdist1top
+    mov       eax, esi
+
+bdist1exit:
+       
+       ;;
+       ;; Get rid of local variables
+       add esp, 32
+       
+       ;; Retore (callee saves convention...)
+       ;;
+       pop edi
+       pop esi
+       pop edx
+       pop ecx
+       pop ebx
+
+       pop ebp                 ; restore stack pointer
+
+       emms                    ; clear mmx registers
+       ret     
+       
+
diff --git a/mpeg2enc/bdist2_mmx.s b/mpeg2enc/bdist2_mmx.s
new file mode 100644 (file)
index 0000000..be1c352
--- /dev/null
@@ -0,0 +1,327 @@
+;
+;  bdist2_mmx.s:  MMX optimized bidirectional squared distance sum
+;
+;  Original believed to be Copyright (C) 2000 Brent Byeler
+;
+;  This program is free software; you can reaxstribute it and/or
+;  modify it under the terms of the GNU General Public License
+;  as published by the Free Software Foundation; either version 2
+;  of the License, or (at your option) any later version.
+;
+;  This program is distributed in the hope that it will be useful,
+;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;  GNU General Public License for more details.
+;
+;  You should have received a copy of the GNU General Public License
+;  along with this program; if not, write to the Free Software
+;  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+;
+
+;/*
+; * squared error between a (16*h) block and a bidirectional
+; * prediction
+; *
+; * p2: address of top left pel of block
+; * pf,hxf,hyf: address and half pel flags of forward ref. block
+; * pb,hxb,hyb: address and half pel flags of backward ref. block
+; * h: height of block
+; * lx: distance (in bytes) of vertically adjacent pels in p2,pf,pb
+; * mmX version
+; */
+
+;int bdist2_mmx(
+;unsigned char *pf, unsigned char *pb, unsigned char *p2,
+;int lx, int hxf, int hyf, int hxb, int hyb, int h)
+;{
+;  unsigned char *pfa,*pfb,*pfc,*pba,*pbb,*pbc;
+;  int s;
+
+; Handy macros for readbility
+
+%define pf [ebp+8]
+%define pb [ebp+12]
+%define p2 [ebp+16]
+%define lx [ebp+20]
+%define hxf [ebp+24]
+%define hyf [ebp+28]
+%define hxb [ebp+32]
+%define hyb [ebp+36]
+%define h   [ebp+40]
+
+
+%define pfa [esp+4]
+%define pfb [esp+8]
+%define pfc [esp+12]
+%define pba [esp+16]
+%define pbb [esp+20]
+%define pbc [esp+24]
+
+SECTION .text
+global bdist2_mmx
+
+align 32
+bdist2_mmx:
+       push ebp                        ; save frame pointer
+       mov ebp, esp            ; link
+       push ebx
+       push ecx
+       push edx
+       push esi     
+       push edi
+
+       ;;
+       ;; Make space for local variables on stack
+       sub       esp, 32
+       
+       mov       edx, hxb
+       mov       eax, hxf
+       mov       esi, lx
+
+       mov       ecx, pf
+       add       ecx, eax
+       mov       pfa, ecx
+       mov       ecx, esi
+       imul      ecx, hyf
+       mov       ebx, pf
+       add       ecx, ebx
+       mov       pfb, ecx
+       add       eax, ecx
+       mov       pfc, eax
+       mov       eax, pb
+       add       eax, edx
+       mov       pba, eax
+       mov       eax, esi
+       imul      eax, hyb
+       mov       ecx, pb
+       add       eax, ecx
+       mov       pbb, eax
+       add       edx, eax
+       mov       pbc, edx
+       xor       esi, esi      ; esi = s (accumulated sym)
+       mov       eax, esi
+
+       mov       edi, h
+       test      edi, edi  ; h = 0?
+       jle       near bdist2exit
+
+       pxor      mm7, mm7
+       pxor      mm6, mm6
+       pcmpeqw   mm5, mm5
+       psubw     mm6, mm5
+       psllw     mm6, 1
+
+bdist2top:
+       mov       eax, pf
+       mov       ebx, pfa
+       mov       ecx, pfb
+       mov       edx, pfc
+       movq      mm0, [eax]
+       movq      mm1, mm0
+       punpcklbw mm0, mm7
+       punpckhbw mm1, mm7
+       movq      mm2, [ebx]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       movq      mm2, [ecx]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       movq      mm2, [edx]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       paddw     mm0, mm6
+       paddw     mm1, mm6
+       psrlw     mm0, 2
+       psrlw     mm1, 2
+
+       mov       eax, pb
+       mov       ebx, pba
+       mov       ecx, pbb
+       mov       edx, pbc
+       movq      mm2, [eax]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       movq      mm4, [ebx]
+       movq      mm5, mm4
+       punpcklbw mm4, mm7
+       punpckhbw mm5, mm7
+       paddw     mm2, mm4
+       paddw     mm3, mm5
+       movq      mm4, [ecx]
+       movq      mm5, mm4
+       punpcklbw mm4, mm7
+       punpckhbw mm5, mm7
+       paddw     mm2, mm4
+       paddw     mm3, mm5
+       movq      mm4, [edx]
+       movq      mm5, mm4
+       punpcklbw mm4, mm7
+       punpckhbw mm5, mm7
+       paddw     mm2, mm4
+       paddw     mm3, mm5
+
+       paddw     mm2, mm6
+       paddw     mm3, mm6
+       psrlw     mm2, 2
+       psrlw     mm3, 2
+
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       psrlw     mm6, 1
+       paddw     mm0, mm6
+       paddw     mm1, mm6
+       psllw     mm6, 1
+       psrlw     mm0, 1
+       psrlw     mm1, 1
+
+       mov       eax, p2
+       movq      mm2, [eax]
+       movq      mm3, mm2
+        punpcklbw mm2, mm7
+        punpckhbw mm3, mm7
+
+        psubw     mm0, mm2
+        psubw     mm1, mm3
+        pmaddwd   mm0, mm0
+        pmaddwd   mm1, mm1
+        paddd     mm0, mm1
+
+       movd      eax, mm0
+       psrlq     mm0, 32
+       movd      ebx, mm0
+       add       esi, eax
+       add       esi, ebx
+
+       mov       eax, pf
+       mov       ebx, pfa
+       mov       ecx, pfb
+       mov       edx, pfc
+       movq      mm0, [eax+8]
+       movq      mm1, mm0
+       punpcklbw mm0, mm7
+       punpckhbw mm1, mm7
+       movq      mm2, [ebx+8]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       movq      mm2, [ecx+8]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       movq      mm2, [edx+8]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       paddw     mm0, mm6
+       paddw     mm1, mm6
+       psrlw     mm0, 2
+       psrlw     mm1, 2
+
+       mov       eax, pb
+       mov       ebx, pba
+       mov       ecx, pbb
+       mov       edx, pbc
+       movq      mm2, [eax+8]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       movq      mm4, [ebx+8]
+       movq      mm5, mm4
+       punpcklbw mm4, mm7
+       punpckhbw mm5, mm7
+       paddw     mm2, mm4
+       paddw     mm3, mm5
+       movq      mm4, [ecx+8]
+       movq      mm5, mm4
+       punpcklbw mm4, mm7
+       punpckhbw mm5, mm7
+       paddw     mm2, mm4
+       paddw     mm3, mm5
+       movq      mm4, [edx+8]
+       movq      mm5, mm4
+       punpcklbw mm4, mm7
+       punpckhbw mm5, mm7
+       paddw     mm2, mm4
+       paddw     mm3, mm5
+       paddw     mm2, mm6
+       paddw     mm3, mm6
+       psrlw     mm2, 2
+       psrlw     mm3, 2
+
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       psrlw     mm6, 1
+       paddW     mm0, mm6
+       paddw     mm1, mm6
+       psllw     mm6, 1
+       psrlw     mm0, 1
+       psrlw     mm1, 1
+
+       mov       eax, p2
+       movq      mm2, [eax+8]
+       movq      mm3, mm2
+        punpcklbw mm2, mm7
+        punpckhbw mm3, mm7
+
+        psubw     mm0, mm2
+        psubw     mm1, mm3
+        pmaddwd   mm0, mm0
+        pmaddwd   mm1, mm1
+        paddd     mm0, mm1
+
+       movd      eax, mm0
+       psrlq     mm0, 32
+       movd      ebx, mm0
+       add       esi, eax
+       add       esi, ebx
+
+    mov       eax, lx
+       add       p2, eax
+       add       pf, eax
+       add       pfa, eax
+       add       pfb, eax
+       add       pfc, eax
+       add       pb, eax
+       add       pba, eax
+       add       pbb, eax
+       add       pbc, eax
+
+       dec       edi
+       jg        near bdist2top
+    mov       eax, esi
+
+bdist2exit:
+       
+       ;;
+       ;; Get rid of local variables
+       add esp, 32
+       
+       ;; Retore (callee saves convention...)
+       ;;
+       pop edi
+       pop esi
+       pop edx
+       pop ecx
+       pop ebx
+
+       pop ebp                 ; restore stack pointer
+
+       emms                    ; clear mmx registers
+       ret     
+       
diff --git a/mpeg2enc/config.h b/mpeg2enc/config.h
new file mode 100644 (file)
index 0000000..8548f87
--- /dev/null
@@ -0,0 +1,37 @@
+/* config.h, configuration defines                                          */
+
+/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */
+
+/*
+ * Disclaimer of Warranty
+ *
+ * These software programs are available to the user without any license fee or
+ * royalty on an "as is" basis.  The MPEG Software Simulation Group disclaims
+ * any and all warranties, whether express, implied, or statuary, including any
+ * implied warranties or merchantability or of fitness for a particular
+ * purpose.  In no event shall the copyright-holder be liable for any
+ * incidental, punitive, or consequential damages of any kind whatsoever
+ * arising from the use of these programs.
+ *
+ * This disclaimer of warranty extends to the user of these programs and user's
+ * customers, employees, agents, transferees, successors, and assigns.
+ *
+ * The MPEG Software Simulation Group does not represent or warrant that the
+ * programs furnished hereunder are free of infringement of any third-party
+ * patents.
+ *
+ * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
+ * are subject to royalty fees to patent holders.  Many of these patents are
+ * general enough such that they are unavoidable regardless of implementation
+ * design.
+ *
+ */
+
+/* define NON_ANSI_COMPILER for compilers without function prototyping */
+/* #define NON_ANSI_COMPILER */
+
+#ifdef NON_ANSI_COMPILER
+#define _ANSI_ARGS_(x) ()
+#else
+#define _ANSI_ARGS_(x) x
+#endif
diff --git a/mpeg2enc/cpu_accel.h b/mpeg2enc/cpu_accel.h
new file mode 100644 (file)
index 0000000..3c64e4c
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * cpu_accel.h
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file was part of mpeg2dec, a free MPEG-2 video stream decoder.
+ *
+ * mpeg2dec is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mpeg2dec is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+
+// x86 accelerations
+#define ACCEL_X86_MMX  0x80000000
+#define ACCEL_X86_3DNOW        0x40000000
+#define ACCEL_X86_MMXEXT       0x20000000
+
+int cpu_accel (void);
diff --git a/mpeg2enc/dist2_mmx.s b/mpeg2enc/dist2_mmx.s
new file mode 100644 (file)
index 0000000..0f41fd8
--- /dev/null
@@ -0,0 +1,600 @@
+;
+;  dist2_mmx.s:  mmX optimized squared distance sum
+;
+;  Original believed to be Copyright (C) 2000 Brent Byeler
+;
+;  This program is free software; you can reaxstribute it and/or
+;  modify it under the terms of the GNU General Public License
+;  as published by the Free Software Foundation; either version 2
+;  of the License, or (at your option) any later version.
+;
+;  This program is distributed in the hope that it will be useful,
+;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;  GNU General Public License for more details.
+;
+;  You should have received a copy of the GNU General Public License
+;  along with this program; if not, write to the Free Software
+;  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+;
+
+; total squared difference between two (16*h) blocks
+; including optional half pel interpolation of [ebp+8] ; blk1 (hx,hy)
+; blk1,blk2: addresses of top left pels of both blocks
+; lx:        distance (in bytes) of vertically adjacent pels
+; hx,hy:     flags for horizontal and/or vertical interpolation
+; h:         height of block (usually 8 or 16)
+; mmX version
+
+global dist2_mmx
+; int dist2_mmx(unsigned char *blk1, unsigned char *blk2,
+;                 int lx, int hx, int hy, int h)
+
+; mm7 = 0
+
+; eax = pblk1 
+; ebx = pblk2
+; ecx = temp
+; edx = distance_sum
+; edi = h
+; esi = lx
+
+               ;; 
+               ;;  private constants needed
+               ;; 
+
+SECTION .data
+align 16
+twos:  
+                       dw      2
+                       dw      2
+                       dw      2
+                       dw      2
+
+align 32
+dist2_mmx:
+       push ebp                        ; save frame pointer
+       mov ebp, esp            ; link
+       push ebx
+       push ecx
+       push edx
+       push esi     
+       push edi
+
+       mov             esi, [ebp+16] ; lx
+       mov     eax, [ebp+20] ; hx
+       mov     edx, [ebp+24] ; hy
+       mov     edi, [ebp+28] ; h
+
+    pxor      mm5, mm5      ; sum
+       test      edi, edi     ; h = 0?
+       jle       near d2exit
+
+       pxor      mm7, mm7     ; get zeros i mm7
+
+       test      eax, eax     ; hx != 0?
+       jne       near d2is10
+       test      edx, edx     ; hy != 0?
+       jne       near d2is10
+
+       mov       eax, [ebp+8]
+    mov       ebx, [ebp+12]
+       jmp      d2top00
+
+align 32
+d2top00:
+        movq      mm0, [eax]
+        movq      mm1, mm0
+        punpcklbw mm0, mm7
+        punpckhbw mm1, mm7
+
+        movq      mm2, [ebx]
+        movq      mm3, mm2
+        punpcklbw mm2, mm7
+        punpckhbw mm3, mm7
+
+        psubw     mm0, mm2
+        psubw     mm1, mm3
+        pmaddwd   mm0, mm0
+        pmaddwd   mm1, mm1
+        paddd     mm0, mm1
+
+        movq      mm1, [eax+8]
+        movq      mm2, mm1
+        punpcklbw mm1, mm7
+        punpckhbw mm2, mm7
+
+        movq      mm3, [ebx+8]
+        movq      mm4, mm3
+        punpcklbw mm3, mm7
+        punpckhbw mm4, mm7
+
+        psubw     mm1, mm3
+        psubw     mm2, mm4
+        pmaddwd   mm1, mm1
+        pmaddwd   mm2, mm2
+        paddd     mm1, mm2
+
+        paddd     mm0, mm1
+       
+               ;; Accumulate sum in edx... we use mm5
+               ;movd     ecx, mm0
+        ;add       edx, ecx
+           ;psrlq        mm0, 32
+           ;movd         ecx, mm0
+        ;add       edx, ecx
+               paddd    mm5, mm0
+
+       add       eax, esi
+       add       ebx, esi
+       dec       edi
+       jg        d2top00
+       jmp       d2exit
+
+
+d2is10:
+       test      eax, eax
+       je        near d2is01
+       test      edx, edx
+       jne       near d2is01
+
+       mov       eax, [ebp+8] ; blk1
+       mov       ebx, [ebp+12] ; blk1
+
+       pxor      mm6, mm6    ; mm6 = 0 and isn't changed anyplace in the loop..
+       pcmpeqw   mm1, mm1
+       psubw     mm6, mm1
+       jmp               d2top10
+       
+align 32
+d2top10:
+       movq      mm0, [eax]
+       movq      mm1, mm0
+       punpcklbw mm0, mm7
+       punpckhbw mm1, mm7
+       movq      mm2, [eax+1]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       paddw     mm0, mm6   ; here we add mm6 = 0.... weird...
+       paddw     mm1, mm6
+       psrlw     mm0, 1
+       psrlw     mm1, 1
+
+       movq      mm2, [ebx]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+
+        psubw     mm0, mm2
+        psubw     mm1, mm3
+        pmaddwd   mm0, mm0
+        pmaddwd   mm1, mm1
+        paddd     mm0, mm1
+
+       movq      mm1, [eax+8]
+       movq      mm2, mm1
+       punpcklbw mm1, mm7
+       punpckhbw mm2, mm7
+       movq      mm3, [eax+9]
+       movq      mm4, mm3
+       punpcklbw mm3, mm7
+       punpckhbw mm4, mm7
+       paddw     mm1, mm3
+       paddw     mm2, mm4
+       paddw     mm1, mm6
+       paddw     mm2, mm6
+       psrlw     mm1, 1
+       psrlw     mm2, 1
+
+       movq      mm3, [ebx+8]
+       movq      mm4, mm3
+        punpcklbw mm3, mm7
+        punpckhbw mm4, mm7
+
+        psubw     mm1, mm3
+        psubw     mm2, mm4
+        pmaddwd   mm1, mm1
+        pmaddwd   mm2, mm2
+        paddd     mm1, mm2
+
+
+       paddd     mm0, mm1
+               ; Accumulate mm0 sum on edx... we'll use mm5 for this and add up at the end
+               ; movd    ecx, mm0
+        ; add       edx, ecx
+               ; psrlq   mm0, 32
+               ; movd    ecx, mm0
+        ; add       edx, ecx
+       paddd     mm5, mm0
+       add       eax, esi
+       add       ebx, esi
+       dec       edi
+       jg        near d2top10
+       
+       
+       jmp       d2exit
+
+d2is01:
+       test      eax, eax
+       jne       near d2is11
+       test      edx, edx
+       je        near d2is11
+
+       mov       eax, [ebp+8] ; blk1
+       mov       edx, [ebp+12] ; blk2
+       mov       ebx, eax
+       add       ebx, esi ;  blk1 + lx
+
+       pxor      mm6, mm6
+       pcmpeqw   mm1, mm1
+       psubw     mm6, mm1  ; mm6 = 1
+       jmp               d2top01
+       
+align 32
+d2top01:
+       movq      mm0, [eax]
+       movq      mm1, mm0
+       punpcklbw mm0, mm7
+       punpckhbw mm1, mm7
+       movq      mm2, [ebx]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       paddw     mm0, mm6
+       paddw     mm1, mm6
+       psrlw     mm0, 1
+       psrlw     mm1, 1
+
+       movq      mm2, [edx]
+       movq      mm3, mm2
+    punpcklbw mm2, mm7
+    punpckhbw mm3, mm7
+
+    psubw     mm0, mm2
+    psubw     mm1, mm3
+
+       pmaddwd   mm0, mm0
+    pmaddwd   mm1, mm1
+    paddd     mm0, mm1
+
+       movq      mm1, [eax+8]
+       movq      mm2, mm1
+       punpcklbw mm1, mm7
+       punpckhbw mm2, mm7
+       
+       movq      mm3, [ebx+8]
+       movq      mm4, mm3
+       punpcklbw mm3, mm7
+       punpckhbw mm4, mm7
+
+       paddw     mm1, mm3
+       paddw     mm2, mm4
+       paddw     mm1, mm6
+       paddw     mm2, mm6
+       psrlw     mm1, 1
+       psrlw     mm2, 1
+
+       movq      mm3, [edx+8]
+       movq      mm4, mm3
+    punpcklbw mm3, mm7
+    punpckhbw mm4, mm7
+
+    psubw     mm1, mm3
+    psubw     mm2, mm4
+
+       pmaddwd   mm1, mm1
+    pmaddwd   mm2, mm2
+    paddd     mm0, mm1
+       paddd     mm0, mm2
+
+       ;; Accumulate in "s" - we use mm5 for the purpose
+       ;;
+       ;movd     ecx, mm0
+    ;add       s, ecx
+       ;psrlq    mm0, 32
+       ;movd     ecx, mm0
+       ;add              s, ecx
+       paddd     mm5, mm0
+
+       ;; Originally this moved 
+       mov       eax, ebx    ; eax = eax + lx
+       add       edx, esi    ; edx = edx + lx
+       add       ebx, esi    ; ebx = ebx + lx
+       dec       edi
+       jg        near d2top01
+       jmp       d2exit
+
+d2is11:
+       mov       eax, [ebp+8] ; blk1
+       mov       edx, [ebp+12] ; blk2
+       mov       ebx, eax  ;  blk1
+       add       ebx, esi  ; ebx = blk1 + lx
+       jmp               d2top11
+       
+align 32
+d2top11:
+       movq      mm0, [eax]
+       movq      mm1, mm0
+       punpcklbw mm0, mm7
+       punpckhbw mm1, mm7
+       movq      mm2, [eax+1]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       movq      mm2, [ebx]
+       movq      mm3, mm2
+       punpcklbw mm2, mm7
+       punpckhbw mm3, mm7
+       movq      mm4, [ebx+1]
+       movq      mm6, mm4
+       punpcklbw mm4, mm7
+       punpckhbw mm6, mm7
+       paddw     mm2, mm4
+       paddw     mm3, mm6
+       paddw     mm0, mm2
+       paddw     mm1, mm3
+       ;pxor         mm6, mm6    ; mm6 = 0
+       ;pcmpeqw          mm5, mm5    ; mm5 = -1
+       ;psubw        mm6, mm5    ; mm6 = 1
+       ;paddw        mm6, mm6    ; mm6 = 2
+       movq      mm6, [twos]
+       paddw     mm0, mm6    ; round mm0
+       paddw     mm1, mm6    ; round mm1
+       psrlw     mm0, 2
+       psrlw     mm1, 2
+
+       movq      mm2, [edx]
+       movq      mm3, mm2
+        punpcklbw mm2, mm7
+        punpckhbw mm3, mm7
+
+        psubw     mm0, mm2
+        psubw     mm1, mm3
+        pmaddwd   mm0, mm0
+        pmaddwd   mm1, mm1
+        paddd     mm0, mm1
+
+       movq      mm1, [eax+8]
+       movq      mm2, mm1
+       punpcklbw mm1, mm7
+       punpckhbw mm2, mm7
+       
+       movq      mm3, [eax+9]
+       movq      mm4, mm3
+       punpcklbw mm3, mm7
+       punpckhbw mm4, mm7
+       
+       paddw     mm1, mm3
+       paddw     mm2, mm4
+       
+       movq      mm3, [ebx+8]
+       movq      mm4, mm3
+       punpcklbw mm3, mm7
+       punpckhbw mm4, mm7
+       paddw     mm1, mm3
+       paddw     mm2, mm4 
+       
+       movq      mm3, [ebx+9]
+       movq      mm4, mm3
+       punpcklbw mm3, mm7
+       punpckhbw mm4, mm7
+
+       paddw     mm1, mm3
+       paddw     mm2, mm4
+
+       ;pxor     mm6, mm6    ; Zero mm6
+       ;pcmpeqw          mm5, mm5    ; mm5 = -1
+       ;psubw    mm6, mm5    ; mm6 = 1
+       ;paddw    mm6, mm6    ; mm6 = 2
+       ;paddw    mm1, mm6    ; round mm1 and mm2
+       ;paddw    mm2, mm6
+       movq      mm6, [twos]
+       paddw     mm1, mm6
+       paddw     mm2, mm6
+       
+       psrlw     mm1, 2
+       psrlw     mm2, 2
+
+       movq      mm3, [edx+8]
+       movq      mm4, mm3
+        punpcklbw mm3, mm7
+        punpckhbw mm4, mm7
+
+        psubw     mm1, mm3
+        psubw     mm2, mm4
+        pmaddwd   mm1, mm1
+        pmaddwd   mm2, mm2
+        paddd     mm1, mm2
+
+       paddd     mm0, mm1
+       
+       ;;
+       ;; Accumulate the result in "s" we use mm6 for the purpose...
+       ;movd     ecx, mm0
+    ;    add       s, ecx
+       ;psrlq    mm0, 32
+       ;movd     ecx, mm0
+       ;add      s, ecx
+       paddd     mm5, mm0
+
+       mov       eax, ebx    ; ahem ebx = eax at start of loop and wasn't changed...
+       add       ebx, esi   
+       add       edx, esi
+       dec       edi
+       jg        near d2top11
+
+
+d2exit:
+       ;; Put the final sum in eax for return...
+       movd      eax, mm5
+       psrlq     mm5, 32
+       movd      ecx, mm5
+    add       eax, ecx
+
+       pop edi
+       pop esi
+       pop edx
+       pop ecx
+       pop ebx
+
+       pop ebp                 ; restore stack pointer
+
+       emms                    ; clear mmx registers
+       ret     
+
+
+; total squared difference between two (8*h) blocks
+; blk1,blk2: addresses of top left pels of both blocks
+; lx:        distance (in bytes) of vertically adjacent pels
+; h:         height of block (usually 4, or 8)
+; mmX version
+
+global dist2_22_mmx
+; int dist2_22_mmx(unsigned char *blk1, unsigned char *blk2,
+;                 int lx, int h)
+
+; mm7 = 0
+
+; eax = pblk1 
+; ebx = pblk2
+; ecx = temp
+; edx = distance_sum
+; edi = h
+; esi = lx
+
+align 32
+dist2_22_mmx:
+       push ebp                        ; save frame pointer
+       mov ebp, esp            ; link
+       push ebx
+       push ecx
+       push edx
+       push esi     
+       push edi
+
+       mov             esi, [ebp+16] ; lx
+       mov     edi, [ebp+20] ; h
+
+    pxor      mm5, mm5      ; sum
+       test      edi, edi     ; h = 0?
+       jle       near d2exit
+
+       pxor      mm7, mm7     ; get zeros i mm7
+
+       mov       eax, [ebp+8]          ; blk1
+    mov       ebx, [ebp+12]            ; blk2
+       jmp      d2top22
+
+align 32
+d2top22:
+        movq      mm0, [eax]
+        movq      mm1, mm0
+        punpcklbw mm0, mm7
+        punpckhbw mm1, mm7
+
+        movq      mm2, [ebx]
+        movq      mm3, mm2
+        punpcklbw mm2, mm7
+        punpckhbw mm3, mm7
+
+        psubw     mm0, mm2
+        psubw     mm1, mm3
+        pmaddwd   mm0, mm0
+        pmaddwd   mm1, mm1
+        paddd     mm5, mm0
+               paddd    mm5, mm1
+
+                       add       eax, esi
+       add       ebx, esi
+       dec       edi
+       jg        d2top22
+       jmp       d2exit
+
+
+; total squared difference between interpolation of two (8*h) blocks and
+; another 8*h block            
+; blk1,blk2: addresses of top left pels of both blocks
+; lx:        distance (in bytes) of vertically adjacent pels
+; h:         height of block (usually 4, or 8)
+; mmX version
+               
+global bdist2_22_mmx
+; int bdist2_22_mmx(unsigned char *blk1f, unsigned char*blk1b,
+;                                 unsigned char *blk2,
+;                 int lx, int h)
+
+; mm7 = 0
+
+; eax = pblk1f 
+; ebx = pblk2
+; ecx = pblk1b
+; edx = distance_sum
+; edi = h
+; esi = lx
+
+align 32
+bdist2_22_mmx:
+       push ebp                        ; save frame pointer
+       mov ebp, esp            ; link
+       push ebx
+       push ecx
+       push edx
+       push esi     
+       push edi
+
+       mov             esi, [ebp+20] ; lx
+       mov     edi, [ebp+24] ; h
+
+    pxor      mm5, mm5      ; sum
+       test      edi, edi     ; h = 0?
+       jle       near d2exit
+
+       pxor      mm7, mm7     ; get zeros i mm7
+
+       mov       eax, [ebp+8]          ; blk1f
+    mov       ebx, [ebp+12]            ; blk1b
+    mov       ecx, [ebp+16]            ; blk2          
+       jmp      bd2top22
+
+align 32
+bd2top22:
+        movq      mm0, [eax]
+        movq      mm1, mm0
+               movq      mm4, [ebx]
+               movq      mm6, mm4
+        punpcklbw mm0, mm7
+        punpckhbw mm1, mm7
+               punpcklbw mm4, mm7
+               punpckhbw mm6, mm7
+
+        movq      mm2, [ecx]
+        movq      mm3, mm2
+        punpcklbw mm2, mm7
+        punpckhbw mm3, mm7
+
+               paddw     mm0, mm4
+               psrlw     mm0, 1
+        psubw     mm0, mm2
+        pmaddwd   mm0, mm0
+               paddw     mm1, mm6
+               psrlw     mm1, 1
+        psubw     mm1, mm3
+        pmaddwd   mm1, mm1
+        paddd     mm5, mm0
+               paddd    mm5, mm1
+
+               add       eax, esi
+               add       ebx, esi
+               add               ecx, esi
+               dec       edi
+               jg        bd2top22
+               jmp       d2exit
+                               
\ No newline at end of file
diff --git a/mpeg2enc/fastintfns.h b/mpeg2enc/fastintfns.h
new file mode 100644 (file)
index 0000000..a52614d
--- /dev/null
@@ -0,0 +1,62 @@
+/* fast int primitives. min,max,abs,samesign
+ *
+ * WARNING: Assumes 2's complement arithmetic.
+ *
+ */
+
+#define fabsshift ((8*sizeof(unsigned int))-1)
+#ifdef P6_CPU
+static __inline__ int intmax( register int x, register int y )
+{
+       asm( "cmpl %1, %0\n"
+            "cmovl %1, %0\n"
+         : "+r" (x) :  "r" (y)
+       );
+       return x;
+}
+
+static __inline__ int intmin( register int x, register int y )
+{
+       asm( "cmpl %1, %0\n"
+            "cmovg %1, %0\n"
+         : "+r" (x) :  "rm" (y)
+       );
+       return x;
+}
+
+static __inline__ int intabs( register int x )
+{
+       register int neg = -x;
+       asm( "cmpl %1, %0\n"
+            "cmovl %1, %0\n"
+         : "+r" (x) :  "r" (neg)
+       );
+       return x;
+}
+#else
+
+static __inline__ int intabs(int x)
+{
+       return ((x)-(((unsigned int)(x))>>fabsshift)) ^ ((x)>>fabsshift);
+}
+
+static __inline__ int intmax(int x, int y)
+{
+       return (((x-y)>>fabsshift) & y) |  ((~((x-y)>>fabsshift)) & x);
+}
+
+static __inline__ int intmin(int x,int y)
+{
+       return (((y-x)>>fabsshift) & y) |  ((~((y-x)>>fabsshift)) & x);
+}
+
+#endif
+
+#define signmask(x) (((int)x)>>fabsshift)
+static __inline__ int intsamesign(int x, int y)
+{
+       return (y+(signmask(x) & -(y<<1)));
+}
+#undef signmask
+#undef fabsshift
+
diff --git a/mpeg2enc/fdct_mmx.s b/mpeg2enc/fdct_mmx.s
new file mode 100644 (file)
index 0000000..3123ca4
--- /dev/null
@@ -0,0 +1,507 @@
+; //////////////////////////////////////////////////////////////////////////////
+; //
+; //  fdctam32.c - AP922 MMX(3D-Now) forward-DCT
+; //  ----------
+; //  Intel Application Note AP-922 - fast, precise implementation of DCT
+; //        http://developer.intel.com/vtune/cbts/appnotes.htm
+; //  ----------
+; //  
+; //       This routine can use a 3D-Now/MMX enhancement to increase the
+; //  accuracy of the fdct_col_4 macro.  The dct_col function uses 3D-Now's
+; //  PMHULHRW instead of MMX's PMHULHW(and POR).  The substitution improves
+; //  accuracy very slightly with performance penalty.  If the target CPU
+; //  does not support 3D-Now, then this function cannot be executed.
+; //  
+; //  For a fast, precise MMX implementation of inverse-DCT 
+; //              visit http://www.elecard.com/peter
+; //
+; //  v1.0 07/22/2000 (initial release)
+; //     
+; //  liaor@iname.com  http://members.tripod.com/~liaor  
+; //////////////////////////////////////////////////////////////////////////////
+
+;;;
+;;; A.Stevens Jul 2000:         ported to nasm syntax and disentangled from
+;;; from Win**** compiler specific stuff.
+;;; All the real work was done above though.
+;;; See above for how to optimise quality on 3DNow! CPU's
+
+               ;;
+               ;;              Macros for code-readability...
+               ;; 
+%define INP eax                ;        pointer to (short *blk) 
+%define OUT ecx                ;        pointer to output (temporary store space qwTemp[])
+%define TABLE ebx      ; pointer to tab_frw_01234567[]
+%define TABLEF ebx  ; pointer to tg_all_16
+%define round_frw_row edx
+
+
+%define x0 INP + 0*16
+%define x1 INP + 1*16
+%define x2 INP + 2*16
+%define x3 INP + 3*16
+%define x4 INP + 4*16
+%define x5 INP + 5*16
+%define x6 INP + 6*16
+%define x7 INP + 7*16
+%define y0 OUT + 0*16
+%define y1 OUT + 1*16
+%define y2 OUT + 2*16
+%define y3 OUT + 3*16
+%define y4 OUT + 4*16
+%define y5 OUT + 5*16
+%define y6 OUT + 6*16
+%define y7 OUT + 7*16
+                               
+               ;;
+               ;; Constants for DCT
+               ;;
+%define BITS_FRW_ACC   3 ; 2 or 3 for accuracy
+%define SHIFT_FRW_COL  BITS_FRW_ACC
+%define SHIFT_FRW_ROW  (BITS_FRW_ACC + 17)
+%define RND_FRW_ROW            (1 << (SHIFT_FRW_ROW-1))
+%define RND_FRW_COL            (1 << (SHIFT_FRW_COL-1))
+
+extern fdct_one_corr           
+extern fdct_r_row                              ;  Defined in C for convenience
+               ;;
+               ;; Concatenated table of forward dct transformation coeffs.
+               ;; 
+extern  fdct_tg_all_16                 ; Defined in C for convenience
+               ;; Offsets into table..
+               
+%define tg_1_16 (TABLEF + 0)
+%define tg_2_16 (TABLEF + 8)
+%define tg_3_16 (TABLEF + 16)
+%define cos_4_16 (TABLEF + 24)
+%define ocos_4_16 (TABLEF + 32)                
+
+               ;;
+               ;; Concatenated table of forward dct coefficients
+               ;; 
+extern tab_frw_01234567                ; Defined in C for convenience
+
+               ;; Offsets into table..
+SECTION .text
+               
+global fdct_mmx
+               
+;;; 
+;;; void fdct_mmx( short *blk )
+;;; 
+
+
+
+;     ////////////////////////////////////////////////////////////////////////
+;     //
+;     // The high-level pseudocode for the fdct_am32() routine :
+;     //
+;     // fdct_am32()
+;     // {
+;     //    forward_dct_col03(); // dct_column transform on cols 0-3
+;     //    forward_dct_col47(); // dct_column transform on cols 4-7
+;     //    for ( j = 0; j < 8; j=j+1 )
+;     //      forward_dct_row1(j); // dct_row transform on row #j
+;     // }
+;     //
+;    
+
+align 32
+fdct_mmx:
+       push ebp                        ; save stack pointer
+       mov ebp, esp            ; link
+
+       push ebx                
+       push ecx                
+       push edx
+       push edi
+                                       
+       mov INP, [ebp+8];               ; input data is row 0 of blk[]
+    ;// transform the left half of the matrix (4 columns)
+
+    lea TABLEF,  [fdct_tg_all_16];
+    mov OUT, INP;
+
+;      lea round_frw_col,  [r_frw_col]
+    ; for ( i = 0; i < 2; i = i + 1)
+    ; the for-loop is executed twice.  We are better off unrolling the 
+    ; loop to avoid branch misprediction.
+mmx32_fdct_col03: 
+    movq mm0, [x1] ; 0 ; x1
+     ;;
+
+    movq mm1, [x6] ; 1 ; x6
+    movq mm2, mm0 ; 2 ; x1
+
+    movq mm3, [x2] ; 3 ; x2
+    paddsw mm0, mm1 ; t1 = x[1] + x[6]
+
+    movq mm4, [x5] ; 4 ; x5
+    psllw mm0, SHIFT_FRW_COL ; t1
+
+    movq mm5, [x0] ; 5 ; x0
+    paddsw mm4, mm3 ; t2 = x[2] + x[5]
+
+    paddsw mm5, [x7] ; t0 = x[0] + x[7]
+    psllw mm4, SHIFT_FRW_COL ; t2
+
+    movq mm6, mm0 ; 6 ; t1
+    psubsw mm2, mm1 ; 1 ; t6 = x[1] - x[6]
+
+    movq mm1,  [tg_2_16] ; 1 ; tg_2_16
+    psubsw mm0, mm4 ; tm12 = t1 - t2
+
+    movq mm7, [x3] ; 7 ; x3
+    pmulhw mm1, mm0 ; tm12*tg_2_16
+
+    paddsw mm7, [x4] ; t3 = x[3] + x[4]
+    psllw mm5, SHIFT_FRW_COL ; t0
+
+    paddsw mm6, mm4 ; 4 ; tp12 = t1 + t2
+    psllw mm7, SHIFT_FRW_COL ; t3
+
+    movq mm4, mm5 ; 4 ; t0
+    psubsw mm5, mm7 ; tm03 = t0 - t3
+
+    paddsw mm1, mm5 ; y2 = tm03 + tm12*tg_2_16
+    paddsw mm4, mm7 ; 7 ; tp03 = t0 + t3
+
+    por mm1,  [fdct_one_corr] ; correction y2 +0.5
+    psllw mm2, SHIFT_FRW_COL+1 ; t6
+
+    pmulhw mm5,  [tg_2_16] ; tm03*tg_2_16
+    movq mm7, mm4 ; 7 ; tp03
+
+    psubsw mm3, [x5] ; t5 = x[2] - x[5]
+    psubsw mm4, mm6 ; y4 = tp03 - tp12
+
+    movq [y2], mm1 ; 1 ; save y2
+    paddsw mm7, mm6 ; 6 ; y0 = tp03 + tp12
+    
+    movq mm1, [x3] ; 1 ; x3
+    psllw mm3, SHIFT_FRW_COL+1 ; t5
+
+    psubsw mm1, [x4] ; t4 = x[3] - x[4]
+    movq mm6, mm2 ; 6 ; t6
+    
+    movq [y4], mm4 ; 4 ; save y4
+    paddsw mm2, mm3 ; t6 + t5
+
+    pmulhw mm2,  [ocos_4_16] ; tp65 = (t6 + t5)*cos_4_16
+    psubsw mm6, mm3 ; 3 ; t6 - t5
+
+    pmulhw mm6,  [ocos_4_16] ; tm65 = (t6 - t5)*cos_4_16
+    psubsw mm5, mm0 ; 0 ; y6 = tm03*tg_2_16 - tm12
+
+    por mm5,  [fdct_one_corr] ; correction y6 +0.5
+    psllw mm1, SHIFT_FRW_COL ; t4
+
+    por mm2,  [fdct_one_corr] ; correction tp65 +0.5
+    movq mm4, mm1 ; 4 ; t4
+
+    movq mm3, [x0] ; 3 ; x0
+    paddsw mm1, mm6 ; tp465 = t4 + tm65
+
+    psubsw mm3, [x7] ; t7 = x[0] - x[7]
+    psubsw mm4, mm6 ; 6 ; tm465 = t4 - tm65
+
+    movq mm0,  [tg_1_16] ; 0 ; tg_1_16
+    psllw mm3, SHIFT_FRW_COL ; t7
+
+    movq mm6,  [tg_3_16] ; 6 ; tg_3_16
+    pmulhw mm0, mm1 ; tp465*tg_1_16
+
+    movq [y0], mm7 ; 7 ; save y0
+    pmulhw mm6, mm4 ; tm465*tg_3_16
+
+    movq [y6], mm5 ; 5 ; save y6
+    movq mm7, mm3 ; 7 ; t7
+
+    movq mm5,  [tg_3_16] ; 5 ; tg_3_16
+    psubsw mm7, mm2 ; tm765 = t7 - tp65
+
+    paddsw mm3, mm2 ; 2 ; tp765 = t7 + tp65
+    pmulhw mm5, mm7 ; tm765*tg_3_16
+
+    paddsw mm0, mm3 ; y1 = tp765 + tp465*tg_1_16
+    paddsw mm6, mm4 ; tm465*tg_3_16
+
+    pmulhw mm3,  [tg_1_16] ; tp765*tg_1_16
+    ;;
+
+    por mm0,  [fdct_one_corr] ; correction y1 +0.5
+    paddsw mm5, mm7 ; tm765*tg_3_16
+
+    psubsw mm7, mm6 ; 6 ; y3 = tm765 - tm465*tg_3_16
+    add INP, 0x08   ; ; increment pointer
+
+    movq [y1], mm0 ; 0 ; save y1
+    paddsw mm5, mm4 ; 4 ; y5 = tm765*tg_3_16 + tm465
+
+    movq [y3], mm7 ; 7 ; save y3
+    psubsw mm3, mm1 ; 1 ; y7 = tp765*tg_1_16 - tp465
+
+    movq [y5], mm5 ; 5 ; save y5
+
+
+mmx32_fdct_col47: ; begin processing last four columns
+    movq mm0, [x1] ; 0 ; x1
+    ;;
+    movq [y7], mm3 ; 3 ; save y7 (columns 0-4)
+    ;;
+
+    movq mm1, [x6] ; 1 ; x6
+    movq mm2, mm0 ; 2 ; x1
+
+    movq mm3, [x2] ; 3 ; x2
+    paddsw mm0, mm1 ; t1 = x[1] + x[6]
+
+    movq mm4, [x5] ; 4 ; x5
+    psllw mm0, SHIFT_FRW_COL ; t1
+
+    movq mm5, [x0] ; 5 ; x0
+    paddsw mm4, mm3 ; t2 = x[2] + x[5]
+
+    paddsw mm5, [x7] ; t0 = x[0] + x[7]
+    psllw mm4, SHIFT_FRW_COL ; t2
+
+    movq mm6, mm0 ; 6 ; t1
+    psubsw mm2, mm1 ; 1 ; t6 = x[1] - x[6]
+
+    movq mm1,  [tg_2_16] ; 1 ; tg_2_16
+    psubsw mm0, mm4 ; tm12 = t1 - t2
+
+    movq mm7, [x3] ; 7 ; x3
+    pmulhw mm1, mm0 ; tm12*tg_2_16
+
+    paddsw mm7, [x4] ; t3 = x[3] + x[4]
+    psllw mm5, SHIFT_FRW_COL ; t0
+
+    paddsw mm6, mm4 ; 4 ; tp12 = t1 + t2
+    psllw mm7, SHIFT_FRW_COL ; t3
+
+    movq mm4, mm5 ; 4 ; t0
+    psubsw mm5, mm7 ; tm03 = t0 - t3
+
+    paddsw mm1, mm5 ; y2 = tm03 + tm12*tg_2_16
+    paddsw mm4, mm7 ; 7 ; tp03 = t0 + t3
+
+    por mm1,  [fdct_one_corr] ; correction y2 +0.5
+    psllw mm2, SHIFT_FRW_COL+1 ; t6
+
+    pmulhw mm5,  [tg_2_16] ; tm03*tg_2_16
+    movq mm7, mm4 ; 7 ; tp03
+
+    psubsw mm3, [x5] ; t5 = x[2] - x[5]
+    psubsw mm4, mm6 ; y4 = tp03 - tp12
+
+    movq [y2+8], mm1 ; 1 ; save y2
+    paddsw mm7, mm6 ; 6 ; y0 = tp03 + tp12
+    
+    movq mm1, [x3] ; 1 ; x3
+    psllw mm3, SHIFT_FRW_COL+1 ; t5
+
+    psubsw mm1, [x4] ; t4 = x[3] - x[4]
+    movq mm6, mm2 ; 6 ; t6
+    
+    movq [y4+8], mm4 ; 4 ; save y4
+    paddsw mm2, mm3 ; t6 + t5
+
+    pmulhw mm2,  [ocos_4_16] ; tp65 = (t6 + t5)*cos_4_16
+    psubsw mm6, mm3 ; 3 ; t6 - t5
+
+    pmulhw mm6,  [ocos_4_16] ; tm65 = (t6 - t5)*cos_4_16
+    psubsw mm5, mm0 ; 0 ; y6 = tm03*tg_2_16 - tm12
+
+    por mm5,  [fdct_one_corr] ; correction y6 +0.5
+    psllw mm1, SHIFT_FRW_COL ; t4
+
+    por mm2,  [fdct_one_corr] ; correction tp65 +0.5
+    movq mm4, mm1 ; 4 ; t4
+
+    movq mm3, [x0] ; 3 ; x0
+    paddsw mm1, mm6 ; tp465 = t4 + tm65
+
+    psubsw mm3, [x7] ; t7 = x[0] - x[7]
+    psubsw mm4, mm6 ; 6 ; tm465 = t4 - tm65
+
+    movq mm0,  [tg_1_16] ; 0 ; tg_1_16
+    psllw mm3, SHIFT_FRW_COL ; t7
+
+    movq mm6,  [tg_3_16] ; 6 ; tg_3_16
+    pmulhw mm0, mm1 ; tp465*tg_1_16
+
+    movq [y0+8], mm7 ; 7 ; save y0
+    pmulhw mm6, mm4 ; tm465*tg_3_16
+
+    movq [y6+8], mm5 ; 5 ; save y6
+    movq mm7, mm3 ; 7 ; t7
+
+    movq mm5,  [tg_3_16] ; 5 ; tg_3_16
+    psubsw mm7, mm2 ; tm765 = t7 - tp65
+
+    paddsw mm3, mm2 ; 2 ; tp765 = t7 + tp65
+    pmulhw mm5, mm7 ; tm765*tg_3_16
+
+    paddsw mm0, mm3 ; y1 = tp765 + tp465*tg_1_16
+    paddsw mm6, mm4 ; tm465*tg_3_16
+
+    pmulhw mm3,  [tg_1_16] ; tp765*tg_1_16
+    ;;
+
+    por mm0, [fdct_one_corr] ; correction y1 +0.5
+    paddsw mm5, mm7 ; tm765*tg_3_16
+
+    psubsw mm7, mm6 ; 6 ; y3 = tm765 - tm465*tg_3_16
+    ;;
+
+    movq [y1+8], mm0 ; 0 ; save y1
+    paddsw mm5, mm4 ; 4 ; y5 = tm765*tg_3_16 + tm465
+
+    movq [y3+8], mm7 ; 7 ; save y3
+    psubsw mm3, mm1 ; 1 ; y7 = tp765*tg_1_16 - tp465
+
+    movq [y5+8], mm5 ; 5 ; save y5
+
+    movq [y7+8], mm3 ; 3 ; save y7
+
+;    emms;
+;    }   ; end of forward_dct_col07() 
+    ;  done with dct_row transform
+
+  
+  ; fdct_mmx32_cols() --
+  ; the following subroutine repeats the row-transform operation, 
+  ; except with different shift&round constants.  This version
+  ; does NOT transpose the output again.  Thus the final output
+  ; is transposed with respect to the source.
+  ;
+  ;  The output is stored into blk[], which destroys the original
+  ;  input data.
+       mov INP,  [ebp+8];              ;; row 0
+        mov edi, 0x08; ;x = 8
+
+       lea TABLE,  [tab_frw_01234567]; ; row 0
+        mov OUT, INP;
+
+       lea round_frw_row,  [fdct_r_row];
+       ; for ( x = 8; x > 0; --x )  ; transform one row per iteration
+
+; ---------- loop begin
+  lp_mmx_fdct_row1:
+    movd mm5,  [INP+12]; ; mm5 = 7 6
+
+    punpcklwd mm5,  [INP+8] ; mm5 =  5 7 4 6
+
+    movq mm2, mm5;     ; mm2 = 5 7 4 6
+    psrlq mm5, 32;     ; mm5 = _ _ 5 7
+
+    movq mm0,  [INP]; ; mm0 = 3 2 1 0
+    punpcklwd mm5, mm2;; mm5 = 4 5 6 7
+
+    movq mm1, mm0;     ; mm1 = 3 2 1 0
+    paddsw mm0, mm5;   ; mm0 = [3+4, 2+5, 1+6, 0+7] (xt3, xt2, xt1, xt0)
+
+    psubsw mm1, mm5;   ; mm1 = [3-4, 2-5, 1-6, 0-7] (xt7, xt6, xt5, xt4)
+    movq mm2, mm0;     ; mm2 = [ xt3 xt2 xt1 xt0 ]
+
+    ;movq [ xt3xt2xt1xt0 ], mm0;
+    ;movq [ xt7xt6xt5xt4 ], mm1;
+
+    punpcklwd mm0, mm1;; mm0 = [ xt5 xt1 xt4 xt0 ]
+
+    punpckhwd mm2, mm1;; mm2 = [ xt7 xt3 xt6 xt2 ]
+    movq mm1, mm2;     ; mm1
+
+    ;; shuffle bytes around
+
+;  movq mm0,  [INP] ; 0 ; x3 x2 x1 x0
+
+;  movq mm1,  [INP+8] ; 1 ; x7 x6 x5 x4
+    movq mm2, mm0 ; 2 ; x3 x2 x1 x0
+
+    movq mm3,  [TABLE] ; 3 ; w06 w04 w02 w00
+    punpcklwd mm0, mm1 ; x5 x1 x4 x0
+
+    movq mm5, mm0 ; 5 ; x5 x1 x4 x0
+    punpckldq mm0, mm0 ; x4 x0 x4 x0  [ xt2 xt0 xt2 xt0 ]
+
+    movq mm4,  [TABLE+8] ; 4 ; w07 w05 w03 w01
+    punpckhwd mm2, mm1 ; 1 ; x7 x3 x6 x2
+
+    pmaddwd mm3, mm0 ; x4*w06+x0*w04 x4*w02+x0*w00
+    movq mm6, mm2 ; 6 ; x7 x3 x6 x2
+
+    movq mm1,  [TABLE+32] ; 1 ; w22 w20 w18 w16
+    punpckldq mm2, mm2 ; x6 x2 x6 x2  [ xt3 xt1 xt3 xt1 ]
+
+    pmaddwd mm4, mm2 ; x6*w07+x2*w05 x6*w03+x2*w01
+    punpckhdq mm5, mm5 ; x5 x1 x5 x1  [ xt6 xt4 xt6 xt4 ]
+
+    pmaddwd mm0,  [TABLE+16] ; x4*w14+x0*w12 x4*w10+x0*w08
+    punpckhdq mm6, mm6 ; x7 x3 x7 x3  [ xt7 xt5 xt7 xt5 ]
+
+    movq mm7,  [TABLE+40] ; 7 ; w23 w21 w19 w17
+    pmaddwd mm1, mm5 ; x5*w22+x1*w20 x5*w18+x1*w16
+;mm3 = a1, a0 (y2,y0)
+;mm1 = b1, b0 (y3,y1)
+;mm0 = a3,a2  (y6,y4)
+;mm5 = b3,b2  (y7,y5)
+
+    paddd mm3,  [round_frw_row] ; +rounder (y2,y0)
+    pmaddwd mm7, mm6 ; x7*w23+x3*w21 x7*w19+x3*w17
+
+    pmaddwd mm2,  [TABLE+24] ; x6*w15+x2*w13 x6*w11+x2*w09
+    paddd mm3, mm4 ; 4 ; a1=sum(even1) a0=sum(even0) ; now ( y2, y0)
+
+    pmaddwd mm5,  [TABLE+48] ; x5*w30+x1*w28 x5*w26+x1*w24
+    ;;
+
+    pmaddwd mm6,  [TABLE+56] ; x7*w31+x3*w29 x7*w27+x3*w25
+    paddd mm1, mm7 ; 7 ; b1=sum(odd1) b0=sum(odd0) ; now ( y3, y1)
+
+    paddd mm0,  [round_frw_row] ; +rounder (y6,y4)
+    psrad mm3, SHIFT_FRW_ROW ; (y2, y0)
+
+    paddd mm1,  [round_frw_row] ; +rounder (y3,y1)
+    paddd mm0, mm2 ; 2 ; a3=sum(even3) a2=sum(even2) ; now (y6, y4)
+
+    paddd mm5,  [round_frw_row] ; +rounder (y7,y5)
+    psrad mm1, SHIFT_FRW_ROW ; y1=a1+b1 y0=a0+b0
+
+    paddd mm5, mm6 ; 6 ; b3=sum(odd3) b2=sum(odd2) ; now ( y7, y5)
+    psrad mm0, SHIFT_FRW_ROW ;y3=a3+b3 y2=a2+b2
+
+    add OUT, 16;  ; increment row-output address by 1 row
+    psrad mm5, SHIFT_FRW_ROW ; y4=a3-b3 y5=a2-b2
+
+    add INP, 16;  ; increment row-address by 1 row
+    packssdw mm3, mm0 ; 0 ; y6 y4 y2 y0
+
+    packssdw mm1, mm5 ; 3 ; y7 y5 y3 y1
+    movq mm6, mm3;    ; mm0 = y6 y4 y2 y0
+
+    punpcklwd mm3, mm1; ; y3 y2 y1 y0
+    sub edi, 0x01;   ; i = i - 1
+    
+    punpckhwd mm6, mm1; ; y7 y6 y5 y4
+    add TABLE,64;  ; increment to next table
+
+    movq  [OUT-16], mm3 ; 1 ; save y3 y2 y1 y0
+
+    movq  [OUT-8], mm6 ; 7 ; save y7 y6 y5 y4
+
+    cmp edi, 0x00;
+    jg near lp_mmx_fdct_row1;  ; begin fdct processing on next row
+               ;; 
+               ;; Tidy up and return
+               ;;
+       pop edi
+       pop edx                 
+       pop ecx                 
+       pop ebx                 
+
+       pop ebp                 ; restore stack pointer
+       emms
+       ret             
+  
\ No newline at end of file
diff --git a/mpeg2enc/global.h b/mpeg2enc/global.h
new file mode 100644 (file)
index 0000000..1cdc556
--- /dev/null
@@ -0,0 +1,690 @@
+/* global.h, global variables, function prototypes                          */
+
+/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */
+
+/*
+ * Disclaimer of Warranty
+ *
+ * These software programs are available to the user without any license fee or
+ * royalty on an "as is" basis.  The MPEG Software Simulation Group disclaims
+ * any and all warranties, whether express, implied, or statuary, including any
+ * implied warranties or merchantability or of fitness for a particular
+ * purpose.  In no event shall the copyright-holder be liable for any
+ * incidental, punitive, or consequential damages of any kind whatsoever
+ * arising from the use of these programs.
+ *
+ * This disclaimer of warranty extends to the user of these programs and user's
+ * customers, employees, agents, transferees, successors, and assigns.
+ *
+ * The MPEG Software Simulation Group does not represent or warrant that the
+ * programs furnished hereunder are free of infringement of any third-party
+ * patents.
+ *
+ * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
+ * are subject to royalty fees to patent holders.  Many of these patents are
+ * general enough such that they are unavoidable regardless of implementation
+ * design.
+ *
+ */
+
+#include "libmpeg3.h"
+#include "mpeg2enc.h"
+#include "quicktime.h"
+
+#include <pthread.h>
+#include <stdint.h>
+
+/* choose between declaration (GLOBAL_ undefined)
+ * and definition (GLOBAL_ defined)
+ * GLOBAL_ is defined in exactly one file (mpeg2enc.c)
+ */
+
+#ifndef GLOBAL_
+#define EXTERN_ extern
+#else
+#define EXTERN_
+#endif
+
+/* global variables */
+
+
+/* zig-zag scan */
+EXTERN_ unsigned char mpeg2_zig_zag_scan[64]
+#ifdef GLOBAL_
+=
+{
+  0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,
+  12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,
+  35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,
+  58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63
+}
+#endif
+;
+
+/* alternate scan */
+EXTERN_ unsigned char alternate_scan[64]
+#ifdef GLOBAL_
+=
+{
+  0,8,16,24,1,9,2,10,17,25,32,40,48,56,57,49,
+  41,33,26,18,3,11,4,12,19,27,34,42,50,58,35,43,
+  51,59,20,28,5,13,6,14,21,29,36,44,52,60,37,45,
+  53,61,22,30,7,15,23,31,38,46,54,62,39,47,55,63
+}
+#endif
+;
+
+/* default intra quantization matrix */
+EXTERN_ uint16_t default_intra_quantizer_matrix[64]
+#ifdef GLOBAL_
+=
+{
+   8, 16, 19, 22, 26, 27, 29, 34,
+  16, 16, 22, 24, 27, 29, 34, 37,
+  19, 22, 26, 27, 29, 34, 34, 38,
+  22, 22, 26, 27, 29, 34, 37, 40,
+  22, 26, 27, 29, 32, 35, 40, 48,
+  26, 27, 29, 32, 35, 40, 48, 58,
+  26, 27, 29, 34, 38, 46, 56, 69,
+  27, 29, 35, 38, 46, 56, 69, 83
+}
+#endif
+;
+
+EXTERN_ uint16_t hires_intra_quantizer_matrix[64]
+#ifdef GLOBAL_
+=
+{
+   8, 16, 18, 20, 24, 25, 26, 30,
+  16, 16, 20, 23, 25, 26, 30, 30,
+  18, 20, 22, 24, 26, 28, 29, 31,
+  20, 21, 23, 24, 26, 28, 31, 31,
+  21, 23, 24, 25, 28, 30, 30, 33,
+  23, 24, 25, 28, 30, 30, 33, 36,
+  24, 25, 26, 29, 29, 31, 34, 38,
+  25, 26, 28, 29, 31, 34, 38, 42
+}
+#endif
+;
+
+/* Our default non intra quantization matrix
+       This is *not* the MPEG default
+        */
+EXTERN_ uint16_t default_nonintra_quantizer_matrix[64]
+#ifdef GLOBAL_
+=
+
+{
+  16, 17, 18, 19, 20, 21, 22, 23,
+  17, 18, 19, 20, 21, 22, 23, 24,
+  18, 19, 20, 21, 22, 23, 24, 25,
+  19, 20, 21, 22, 23, 24, 26, 27,
+  20, 21, 22, 23, 25, 26, 27, 28,
+  21, 22, 23, 24, 26, 27, 28, 30,
+  22, 23, 24, 26, 27, 28, 30, 31,
+  23, 24, 25, 27, 28, 30, 31, 33
+}   
+#endif
+;
+
+/* Hires non intra quantization matrix.  THis *is*
+       the MPEG default...      */
+EXTERN_ uint16_t hires_nonintra_quantizer_matrix[64]
+#ifdef GLOBAL_
+=
+{
+       16, 16, 16, 16, 16, 16, 16, 16,
+       16, 16, 16, 16, 16, 16, 16, 16,
+       16, 16, 16, 16, 16, 16, 16, 16,
+       16, 16, 16, 16, 16, 16, 16, 16,
+       16, 16, 16, 16, 16, 16, 16, 16,
+       16, 16, 16, 16, 16, 16, 16, 16,
+       16, 16, 16, 16, 16, 16, 16, 16,
+       16, 16, 16, 16, 16, 16, 16, 16
+}
+#endif
+;
+
+/* non-linear quantization coefficient table */
+EXTERN_ unsigned char non_linear_mquant_table[32]
+#ifdef GLOBAL_
+=
+{
+   0, 1, 2, 3, 4, 5, 6, 7,
+   8,10,12,14,16,18,20,22,
+  24,28,32,36,40,44,48,52,
+  56,64,72,80,88,96,104,112
+}
+#endif
+;
+
+/* non-linear mquant table for mapping from scale to code
+ * since reconstruction levels are not bijective with the index map,
+ * it is up to the designer to determine most of the quantization levels
+ */
+
+EXTERN_ unsigned char map_non_linear_mquant[113] 
+#ifdef GLOBAL_
+=
+{
+0,1,2,3,4,5,6,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,
+16,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,22,22,
+22,22,23,23,23,23,24,24,24,24,24,24,24,25,25,25,25,25,25,25,26,26,
+26,26,26,26,26,26,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,29,
+29,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,31,31,31,31,31
+}
+#endif
+;
+
+struct mc_result
+{
+       uint16_t weight;
+       int8_t x;
+       int8_t y;
+};
+
+typedef struct mc_result mc_result_s;
+
+typedef struct motion_comp
+{
+       uint8_t **oldorg, **neworg;
+       uint8_t **oldref, **newref;
+       uint8_t **cur, **curref;
+       int sxf, syf, sxb, syb;
+} motion_comp_s;
+
+typedef struct mbinfo mbinfo_s;
+
+typedef struct pict_data
+{
+
+       /* picture structure (header) data */
+
+       int temp_ref; /* temporal reference */
+       int pict_type; /* picture coding type (I, P or B) */
+       int vbv_delay; /* video buffering verifier delay (1/90000 seconds) */
+       int forw_hor_f_code, forw_vert_f_code;
+       int back_hor_f_code, back_vert_f_code; /* motion vector ranges */
+       int dc_prec;                            /* DC coefficient prec for intra blocks */
+       int pict_struct;                        /* picture structure (frame, top / bottom) */
+       int topfirst;                           /* display top field first */
+       int frame_pred_dct;                     /* Use only frame prediction... */
+       int intravlc;                           /* Intra VLC format */
+       int q_scale_type;                       /* Quantiser scale... */
+       int altscan;                            /* Alternate scan  */
+       int repeatfirst;                        /* repeat first field after second field */
+       int prog_frame;                         /* progressive frame */
+
+       /* 8*8 block data, raw (unquantised) and quantised, and (eventually but
+          not yet inverse quantised */
+       int16_t (*blocks)[64];
+       int16_t (*qblocks)[64];
+
+       unsigned char **curorg, **curref;
+       /* macroblock side information array */
+       mbinfo_s *mbinfo;
+       /* motion estimation parameters */
+} pict_data_s;
+
+typedef struct
+{
+       int start_row, end_row;
+       pthread_mutex_t input_lock, output_lock;
+       pthread_t tid;   /* ID of thread */
+       int done;
+
+       motion_comp_s *motion_comp;
+       pict_data_s *pict_data;
+       int secondfield;
+       int ipflag;
+
+#define MAX_44_MATCHES (256*256/(4*4))
+       int sub22_num_mcomps;
+       int sub44_num_mcomps;
+       mc_result_s sub44_mcomps[MAX_44_MATCHES];
+       mc_result_s sub22_mcomps[MAX_44_MATCHES*4];
+} motion_engine_t;
+
+#if 0
+typedef struct
+{
+  pthread_mutex_t ratectl_lock;
+
+  double R, T, d;
+  double actsum;
+  int Np, Nb;
+  double S, Q;
+  int prev_mquant;
+  double bitcnt_EOP;
+  double next_ip_delay; /* due to frame reordering delay */
+  double decoding_time;
+  int Xi, Xp, Xb, r, d0i, d0p, d0b;
+  double avg_act;
+} ratectl_t;
+#endif
+
+typedef struct
+{
+/*
+ *   bitcnt_EOP = 0.0;
+ *   next_ip_delay = 0.0;
+ *   decoding_time = 0.0;
+ *   P =                                         0;  // P distance between complete intra slice refresh 
+ *   r =                                         0;  // r (reaction parameter) 
+ *   avg_act =                           0;  // avg_act (initial average activity) 
+ *   Xi =                                        0;  // Xi (initial I frame global complexity measure) 
+ *   Xp =                                        0;  // Xp (initial P frame global complexity measure) 
+ *   Xb =                                        0;  // Xb (initial B frame global complexity measure) 
+ *   d0i =                               0;  // d0i (initial I frame virtual buffer fullness) 
+ *   d0p =                               0;  // d0p (initial P frame virtual buffer fullness) 
+ *   d0b =                               0;  // d0b (initial B frame virtual buffer fullness) 
+ */
+  pthread_mutex_t ratectl_lock;
+
+  double Xi, Xp, Xb;
+  int r;
+  int d0i, d0pb;
+  double R;
+  int d;
+  double T;
+  int CarryR;
+  int CarryRLim;
+
+/* bitcnt_EOP - Position in generated bit-stream for latest
+                       end-of-picture Comparing these values with the
+                       bit-stream position for when the picture is due to be
+                       displayed allows us to see what the vbv buffer is up
+                       to.
+
+   gop_undershoot - If we *undershoot* our bit target the vbv buffer
+                               calculations based on the actual length of the
+                               bitstream will be wrong because in the final system
+                               stream these bits will be padded away.  I.e. frames
+                               *won't* arrive as early as the length of the video
+                               stream would suggest they would.  To get it right we
+                               have to keep track of the bits that would appear in
+                               padding.
+                       
+                                                                       
+*/
+
+  int64_t bitcnt_EOP;
+  int gop_undershoot;
+
+/*
+  actsum - Total activity (sum block variances) in frame
+  actcovered - Activity macroblocks so far quantised (used to
+                        fine tune quantisation to avoid starving highly
+                  active blocks appearing late in frame...) UNUSED
+  avg_act - Current average activity...
+*/
+  double actsum;
+  double actcovered;
+  double sum_avg_act;
+  double avg_act;
+  double peak_act;
+
+  int Np, Nb;
+  int64_t S;
+  double IR;
+
+/* Note: eventually we may wish to tweak these to suit image content */
+  double Ki;   /* Down-scaling of I/B/P-frame complexity */
+  double Kb;   /* relative to others in bit-allocation   */
+  double Kp;   /* calculations.  We only need 2 but have all
+                                                  3 for readability */
+
+  int min_d,max_d;
+  int min_q, max_q;
+
+/* TODO EXPERIMENT */
+  double avg_KI;  /* TODO: These values empirically determined           */
+  double avg_KB;   /* for MPEG-1, may need tuning for MPEG-2   */
+  double avg_KP;
+#define K_AVG_WINDOW_I 4.0     /* TODO: MPEG-1, hard-wired settings */
+#define K_AVG_WINDOW_P   10.0
+#define K_AVG_WINDOW_B   20.0
+  double bits_per_mb;
+
+  double SQ;
+  double AQ;
+
+       double current_quant;
+       int64_t frame_start;
+       int64_t frame_end;
+} ratectl_t;
+
+typedef struct
+{
+  int start_row, end_row;
+  pthread_mutex_t input_lock, output_lock;
+  pthread_t tid;   /* ID of thread */
+  int done;
+
+  pict_data_s *picture;
+  unsigned char **pred;
+  unsigned char **cur;
+// Temp for MMX
+  unsigned char temp[128];
+} transform_engine_t;
+
+typedef struct
+{
+       int start_row, end_row;
+       pthread_mutex_t input_lock, output_lock;
+       pthread_t tid;   /* ID of thread */
+       int done;
+
+       int prev_mquant;
+
+/* prediction values for DCT coefficient (0,0) */
+       int dc_dct_pred[3];
+       
+       unsigned char *frame;
+       unsigned char *slice_buffer;
+       long slice_size;
+       long slice_allocated;
+       pict_data_s *picture;
+       ratectl_t *ratectl;
+       unsigned char outbfr;
+       int outcnt;
+} slice_engine_t;
+
+EXTERN_ pthread_mutex_t test_lock;
+EXTERN_ motion_engine_t *motion_engines;
+EXTERN_ transform_engine_t *transform_engines;
+EXTERN_ transform_engine_t *itransform_engines;
+EXTERN_ slice_engine_t *slice_engines;
+EXTERN_ ratectl_t **ratectl;
+EXTERN_ int quiet; /* suppress warnings */
+
+
+
+
+EXTERN_ pict_data_s cur_picture;
+
+/* reconstructed frames */
+EXTERN_ unsigned char *newrefframe[3], *oldrefframe[3], *auxframe[3];
+/* original frames */
+EXTERN_ unsigned char *neworgframe[3], *oldorgframe[3], *auxorgframe[3];
+/* prediction of current frame */
+EXTERN_ unsigned char *predframe[3];
+/* motion estimation parameters */
+EXTERN_ struct motion_data *motion_data;
+
+/* SCale factor for fast integer arithmetic routines */
+/* Changed this and you *must* change the quantisation routines as they depend on its absolute
+       value */
+#define IQUANT_SCALE_POW2 16
+#define IQUANT_SCALE (1<<IQUANT_SCALE_POW2)
+#define COEFFSUM_SCALE (1<<16)
+
+/* Orginal intra / non_intra quantization matrices */
+EXTERN_ uint16_t intra_q[64], inter_q[64];
+EXTERN_ uint16_t i_intra_q[64], i_inter_q[64];
+
+/* Table driven intra / non-intra quantization matrices */
+EXTERN_ uint16_t intra_q_tbl[113][64], inter_q_tbl[113][64];
+EXTERN_ uint16_t i_intra_q_tbl[113][64], i_inter_q_tbl[113][64];
+EXTERN_ float intra_q_tblf[113][64], inter_q_tblf[113][64];
+EXTERN_ float i_intra_q_tblf[113][64], i_inter_q_tblf[113][64];
+
+EXTERN_ uint16_t chrom_intra_q[64],chrom_inter_q[64];
+
+
+
+
+
+/* clipping (=saturation) table */
+EXTERN_ unsigned char *clp;
+
+/* name strings */
+EXTERN_ char id_string[256], tplorg[256], tplref[256], out_path[256];
+EXTERN_ char iqname[256], niqname[256];
+EXTERN_ char statname[256];
+EXTERN_ char errortext[256];
+
+EXTERN_ FILE *outfile; /* file descriptors */
+EXTERN_ FILE *statfile; /* file descriptors */
+EXTERN_ int inputtype; /* format of input frames */
+
+/*
+  How many frames to read ahead (eventually intended to support
+  scene change based GOP structuring.  READ_LOOK_AHEAD/2 must be
+  greater than M (otherwise buffers will be overwritten that are
+  still in use).
+
+  It should also be a multiple of 4 due to the way buffers are
+  filled (in 1/4's).
+*/
+
+#define READ_LOOK_AHEAD 4 
+EXTERN_ uint8_t ***frame_buffers;
+
+
+/* These determine what input format to use */
+EXTERN_ quicktime_t *qt_file;
+EXTERN_ mpeg3_t *mpeg_file;
+EXTERN_ int do_stdin;
+EXTERN_ FILE *stdin_fd;
+
+
+EXTERN_ int do_buffers;
+EXTERN_ pthread_mutex_t input_lock;
+EXTERN_ pthread_mutex_t output_lock;
+EXTERN_ pthread_mutex_t copy_lock;
+EXTERN_ char *input_buffer_y;
+EXTERN_ char *input_buffer_u;
+EXTERN_ char *input_buffer_v;
+EXTERN_ int input_buffer_end;
+
+
+EXTERN_ int verbose;
+EXTERN_ quicktime_t *qt_output;
+EXTERN_ unsigned char *frame_buffer;
+EXTERN_ unsigned char **row_pointers;
+EXTERN_ int fixed_mquant;
+EXTERN_ double quant_floor;                    /* quantisation floor [1..10] (0 for CBR) */
+EXTERN_ double act_boost;              /* Quantisation reduction for highly active blocks */
+EXTERN_ int use_hires_quant;
+EXTERN_ int use_denoise_quant;
+/* Number of processors */
+EXTERN_ int processors;
+EXTERN_ long start_frame, end_frame;    /* Range to encode in source framerate units */
+EXTERN_ int seq_header_every_gop;
+
+/* coding model parameters */
+
+EXTERN_ int N; /* number of frames in Group of Pictures */
+EXTERN_ int M; /* distance between I/P frames */
+EXTERN_ int P; /* intra slice refresh interval */
+EXTERN_ int nframes; /* total number of frames to encode */
+EXTERN_ long frames_scaled; /* frame count normalized to output frame rate */
+EXTERN_ int frame0, tc0; /* number and timecode of first frame */
+EXTERN_ int mpeg1; /* ISO/IEC IS 11172-2 sequence */
+EXTERN_ int fieldpic; /* use field pictures */
+
+/* sequence specific data (sequence header) */
+
+EXTERN_ int qsubsample_offset, 
+           fsubsample_offset,
+              rowsums_offset,
+              colsums_offset;          /* Offset from picture buffer start of sub-sampled data... */
+EXTERN_ int mb_per_pict;                       /* Number of macro-blocks in a picture */                                                     
+EXTERN_ int fast_mc_frac;       /* inverse proportion of fast motion estimates
+                                                        consider in detail */
+EXTERN_ int mc_44_red;                 /* Sub-mean population reduction passes for 4x4 and 2x2 */
+EXTERN_ int mc_22_red;                 /* Motion compensation stages                                           */
+
+
+
+EXTERN_ int horizontal_size, vertical_size; /* frame size (pels) */
+EXTERN_ int width, height; /* encoded frame size (pels) multiples of 16 or 32 */
+EXTERN_ int chrom_width, chrom_height, block_count;
+EXTERN_ int mb_width, mb_height; /* frame size (macroblocks) */
+EXTERN_ int width2, height2, mb_height2, chrom_width2; /* picture size adjusted for interlacing */
+EXTERN_ int aspectratio; /* aspect ratio information (pel or display) */
+EXTERN_ int frame_rate_code; /* coded value of frame rate */
+EXTERN_ int dctsatlim;                 /* Value to saturated DCT coeffs to */
+EXTERN_ double frame_rate; /* frames per second */
+EXTERN_ double input_frame_rate; /* input frame rate */
+EXTERN_ double bit_rate; /* bits per second */
+EXTERN_ int video_buffer_size;
+EXTERN_ int vbv_buffer_size; /* size of VBV buffer (* 16 kbit) */
+EXTERN_ int constrparms; /* constrained parameters flag (MPEG-1 only) */
+EXTERN_ int load_iquant, load_niquant; /* use non-default quant. matrices */
+EXTERN_ int load_ciquant,load_cniquant;
+
+
+/* sequence specific data (sequence extension) */
+
+EXTERN_ int profile, level; /* syntax / parameter constraints */
+EXTERN_ int prog_seq; /* progressive sequence */
+EXTERN_ int chroma_format;
+EXTERN_ int low_delay; /* no B pictures, skipped pictures */
+
+
+/* sequence specific data (sequence display extension) */
+
+EXTERN_ int video_format; /* component, PAL, NTSC, SECAM or MAC */
+EXTERN_ int color_primaries; /* source primary chromaticity coordinates */
+EXTERN_ int transfer_characteristics; /* opto-electronic transfer char. (gamma) */
+EXTERN_ int matrix_coefficients; /* Eg,Eb,Er / Y,Cb,Cr matrix coefficients */
+EXTERN_ int display_horizontal_size, display_vertical_size; /* display size */
+
+
+/* picture specific data (picture coding extension) */
+EXTERN_ int opt_dc_prec;
+EXTERN_ int opt_prog_frame;
+EXTERN_ int opt_repeatfirst;
+EXTERN_ int opt_topfirst;
+
+/* use only frame prediction and frame DCT (I,P,B,current) */
+EXTERN_ int frame_pred_dct_tab[3];
+EXTERN_ int conceal_tab[3]; /* use concealment motion vectors (I,P,B) */
+EXTERN_ int qscale_tab[3]; /* linear/non-linear quantizaton table */
+EXTERN_ int intravlc_tab[3]; /* intra vlc format (I,P,B,current) */
+EXTERN_ int altscan_tab[3]; /* alternate scan (I,P,B,current) */
+
+/* prototypes of global functions */
+
+/* conform.c */
+void range_checks _ANSI_ARGS_((void));
+void profile_and_level_checks _ANSI_ARGS_(());
+
+/* fdctref.c */
+void init_fdct _ANSI_ARGS_((void));
+
+/* idct.c */
+void init_idct _ANSI_ARGS_((void));
+
+/* motion.c */
+void motion_estimation _ANSI_ARGS_((pict_data_s *picture,
+       motion_comp_s *mc_data,
+       int secondfield, int ipflag));
+
+/* mpeg2enc.c */
+void error _ANSI_ARGS_((char *text));
+
+/* predict.c */
+void predict _ANSI_ARGS_((pict_data_s *picture, 
+                        uint8_t *reff[],
+                        uint8_t *refb[],
+                        uint8_t *cur[3],
+                        int secondfield));
+
+/* putbits.c */
+void slice_initbits(slice_engine_t *engine);
+void slice_putbits(slice_engine_t *engine, long val, int n);
+void slice_alignbits(slice_engine_t *engine);
+void slice_finishslice(slice_engine_t *engine);
+
+
+void mpeg2_initbits _ANSI_ARGS_((void));
+void putbits _ANSI_ARGS_((int val, int n));
+void alignbits _ANSI_ARGS_((void));
+double bitcount _ANSI_ARGS_((void));
+
+/* puthdr.c */
+void putseqhdr _ANSI_ARGS_((void));
+void putseqext _ANSI_ARGS_((void));
+void putseqdispext _ANSI_ARGS_((void));
+void putuserdata _ANSI_ARGS_((char *userdata));
+void putgophdr _ANSI_ARGS_((int frame, int closed_gop));
+void putpicthdr _ANSI_ARGS_((pict_data_s *picture));
+void putpictcodext _ANSI_ARGS_((pict_data_s *picture));
+void putseqend _ANSI_ARGS_((void));
+
+/* putmpg.c */
+void putintrablk _ANSI_ARGS_((slice_engine_t *engine, pict_data_s *picture, short *blk, int cc));
+void putnonintrablk _ANSI_ARGS_((slice_engine_t *engine, pict_data_s *picture, short *blk));
+void putmv _ANSI_ARGS_((slice_engine_t *engine, int dmv, int f_code));
+
+/* putpic.c */
+void putpict _ANSI_ARGS_((pict_data_s *picture));
+
+/* putseq.c */
+void putseq _ANSI_ARGS_((void));
+
+/* putvlc.c */
+void putDClum _ANSI_ARGS_((slice_engine_t *engine, int val));
+void putDCchrom _ANSI_ARGS_((slice_engine_t *engine, int val));
+void putACfirst _ANSI_ARGS_((slice_engine_t *engine, int run, int val));
+void putAC _ANSI_ARGS_((slice_engine_t *engine, int run, int signed_level, int vlcformat));
+void putaddrinc _ANSI_ARGS_((slice_engine_t *engine, int addrinc));
+void putmbtype _ANSI_ARGS_((slice_engine_t *engine, int pict_type, int mb_type));
+void putmotioncode _ANSI_ARGS_((slice_engine_t *engine, int motion_code));
+void putdmv _ANSI_ARGS_((slice_engine_t *engine, int dmv));
+void putcbp _ANSI_ARGS_((slice_engine_t *engine, int cbp));
+
+extern int (*pquant_non_intra)(pict_data_s *picture, int16_t *src, int16_t *dst,
+                                               int mquant, int *nonsat_mquant);
+
+extern int (*pquant_weight_coeff_sum)(int16_t *blk, uint16_t*i_quant_mat );
+
+/* quantize.c */
+
+void iquantize( pict_data_s *picture );
+void quant_intra (     pict_data_s *picture,
+                                       int16_t *src, int16_t *dst, 
+                                       int mquant, int *nonsat_mquant);
+int quant_non_intra( pict_data_s *picture,
+                                                  int16_t *src, int16_t *dst,
+                                                       int mquant, int *nonsat_mquant);
+void iquant_intra ( int16_t *src, int16_t *dst, int dc_prec, int mquant);
+void iquant_non_intra (int16_t *src, int16_t *dst, int mquant);
+void init_quantizer();
+int  next_larger_quant( pict_data_s *picture, int quant );
+
+extern int (*pquant_non_intra)(pict_data_s *picture, int16_t *src, int16_t *dst,
+                                               int mquant, int *nonsat_mquant);
+
+extern int (*pquant_weight_coeff_sum)(int16_t *blk, uint16_t*i_quant_mat );
+
+/* ratectl.c */
+void ratectl_init_seq _ANSI_ARGS_((ratectl_t *ratectl));
+void ratectl_init_GOP _ANSI_ARGS_((ratectl_t *ratectl, int np, int nb));
+void ratectl_init_pict _ANSI_ARGS_((ratectl_t *ratectl, pict_data_s *picture));
+void ratectl_update_pict _ANSI_ARGS_((ratectl_t *ratectl, pict_data_s *picture));
+int ratectl_start_mb _ANSI_ARGS_((ratectl_t *ratectl, pict_data_s *picture));
+int ratectl_calc_mquant _ANSI_ARGS_((ratectl_t *ratectl, pict_data_s *picture, int j));
+void vbv_end_of_picture _ANSI_ARGS_((void));
+void calc_vbv_delay _ANSI_ARGS_((void));
+
+/* readpic.c */
+void readframe _ANSI_ARGS_((int frame_num, uint8_t *frame[]));
+
+/* stats.c */
+void calcSNR _ANSI_ARGS_((unsigned char *org[3], unsigned char *rec[3]));
+void stats _ANSI_ARGS_((void));
+
+/* transfrm.c */
+void transform _ANSI_ARGS_((pict_data_s *picture,
+                               uint8_t *pred[], 
+                               uint8_t *cur[]));
+void itransform _ANSI_ARGS_((pict_data_s *picture,
+                                 uint8_t *pred[], uint8_t *cur[]));
+void dct_type_estimation _ANSI_ARGS_((pict_data_s *picture,
+       uint8_t *pred, uint8_t *cur));
+
diff --git a/mpeg2enc/idct_mmx.s b/mpeg2enc/idct_mmx.s
new file mode 100644 (file)
index 0000000..4387dc0
--- /dev/null
@@ -0,0 +1,739 @@
+;
+; MMX32 iDCT algorithm  (IEEE-1180 compliant) :: idct_mmx32()
+;
+; MPEG2AVI
+; --------
+;  v0.16B33 initial release
+;
+; This was one of the harder pieces of work to code.
+; Intel's app-note focuses on the numerical issues of the algorithm, but
+; assumes the programmer is familiar with IDCT mathematics, leaving the
+; form of the complete function up to the programmer's imagination.
+;
+;  ALGORITHM OVERVIEW
+;  ------------------
+; I played around with the code for quite a few hours.  I came up
+; with *A* working IDCT algorithm, however I'm not sure whether my routine
+; is "the correct one."  But rest assured, my code passes all six IEEE 
+; accuracy tests with plenty of margin.
+;
+;   My IDCT algorithm consists of 4 steps:
+;
+;   1) IDCT-row transformation (using the IDCT-row function) on all 8 rows
+;      This yields an intermediate 8x8 matrix.
+;
+;   2) intermediate matrix transpose (mandatory)
+;
+;   3) IDCT-row transformation (2nd time) on all 8 rows of the intermediate
+;      matrix.  The output is the final-result, in transposed form.
+;
+;   4) post-transformation matrix transpose 
+;      (not necessary if the input-data is already transposed, this could
+;       be done during the MPEG "zig-zag" scan, but since my algorithm
+;       requires at least one transpose operation, why not re-use the
+;       transpose-code.)
+;
+;   Although the (1st) and (3rd) steps use the SAME row-transform operation,
+;   the (3rd) step uses different shift&round constants (explained later.)
+;
+;   Also note that the intermediate transpose (2) would not be neccessary,
+;   if the subsequent operation were a iDCT-column transformation.  Since
+;   we only have the iDCT-row transform, we transpose the intermediate
+;   matrix and use the iDCT-row transform a 2nd time.
+;
+;   I had to change some constants/variables for my method to work :
+;
+;      As given by Intel, the #defines for SHIFT_INV_COL and RND_INV_COL are
+;      wrong.  Not surprising since I'm not using a true column-transform 
+;      operation, but the row-transform operation (as mentioned earlier.)
+;      round_inv_col[], which is given as "4 short" values, should have the
+;      same dimensions as round_inv_row[].  The corrected variables are 
+;      shown.
+;
+;      Intel's code defines a different table for each each row operation.
+;      The tables given are 0/4, 1/7, 2/6, and 5/3.  My code only uses row#0.
+;      Using the other rows messes up the overall transform.
+;
+;   IMPLEMENTATION DETAILs
+;   ----------------------
+; 
+;   I divided the algorithm's work into two subroutines,
+;    1) idct_mmx32_rows() - transforms 8 rows, then transpose
+;    2) idct_mmx32_cols() - transforms 8 rows, then transpose
+;       yields final result ("drop-in" direct replacement for INT32 IDCT)
+;
+;   The 2nd function is a clone of the 1st, with changes made only to the
+;   shift&rounding instructions.
+;
+;      In the 1st function (rows), the shift & round instructions use 
+;       SHIFT_INV_ROW & round_inv_row[] (renamed to r_inv_row[])
+;
+;      In the 2nd function (cols)-> r_inv_col[], and
+;       SHIFT_INV_COL & round_inv_col[] (renamed to r_inv_col[])
+;
+;   Each function contains an integrated transpose-operator, which comes
+;   AFTER the primary transformation operation.  In the future, I'll optimize
+;   the code to do more of the transpose-work "in-place".  Right now, I've
+;   left the code as two subroutines and a main calling function, so other
+;   people can read the code more easily.
+;
+;   liaor@umcc.ais.org  http:;members.tripod.com/~liaor
+;  
+
+;;;
+;;; A.Stevens Jul 2000 easy-peasy quick port to nasm
+;;; Isn't open source a sensible idea...
+;;; 
+
+;=============================================================================
+;
+;  AP-922   http:;developer.intel.com/vtune/cbts/strmsimd
+; These examples contain code fragments for first stage iDCT 8x8
+; (for rows) and first stage DCT 8x8 (for columns)
+;
+;============================================================================
+               
+%define INP eax                ; pointer to (short *blk)
+%define OUT ecx                ; pointer to output (temporary store space qwTemp[])
+%define TABLE ebx      ; pointer to idct_tab_01234567[]
+%define round_inv_row edx
+%define round_inv_col edx
+
+               
+%define ROW_STRIDE 16                                                  ; for 8x8 matrix transposer
+%define BITS_INV_ACC   4                                               ; 4 or 5 for IEEE
+%define SHIFT_INV_ROW  (16 - BITS_INV_ACC)
+%define SHIFT_INV_COL  (1 + BITS_INV_ACC +14 ) ;  changed from Intel's val)
+
+               ;;
+               ;; Variables and tables defined in C for convenience
+               ;;
+extern idct_r_inv_row                          ; 2 DWORDSs
+extern  idct_r_inv_col                         ;    "
+extern  idct_r_inv_corr                                ;    "
+extern idct_tab_01234567               ; Catenated table of coefficients
+               
+               ;; 
+               ;;  private variables and functions
+               ;; 
+
+SECTION .bss
+align 16
+; qwTemp:              resw 64                         ; temporary storage space, 8x8 of shorts
+
+               
+SECTION .text
+               
+               ;; static void idct_mmx( short *blk 
+global idct_mmx
+
+idct_mmx:
+       push ebp                        ; save frame pointer
+       mov ebp, esp            ; link
+
+       push ebx                
+       push ecx                
+       push edx
+       push edi
+               
+               ;; 
+               ;; transform all 8 rows of 8x8 iDCT block
+               ;;
+
+       ; this subroutine performs two operations
+       ; 1) iDCT row transform
+       ;               for( i = 0; i < 8; ++ i)
+       ;                       DCT_8_INV_ROW_1( blk[i*8], qwTemp[i] );
+       ;
+       ; 2) transpose the matrix (which was stored in qwTemp[])
+       ;        qwTemp[] -> [8x8 matrix transpose] -> blk[]
+
+       mov INP, [ebp+8]                        ; INP = blk
+       mov edi, 0x00;                          ; x = 0
+       lea TABLE,[idct_tab_01234567]; ; row 0
+
+
+;      lea OUT,   [qwTemp];
+       mov OUT,    [ebp+12];
+       lea round_inv_row,   [idct_r_inv_row]
+    jmp lpa
+                               
+       ; for ( x = 0; x < 8; ++x )  ; transform one row per iteration
+align 32               
+lpa:
+       movq mm0,   [INP]               ; 0 ; x3 x2 x1 x0
+
+       movq mm1,   [INP+8]     ; 1 ; x7 x6 x5 x4
+       movq mm2, mm0 ;                         ; 2 ; x3 x2 x1 x0
+
+       movq mm3,   [TABLE]     ; 3 ; w06 w04 w02 w00
+       punpcklwd mm0, mm1                      ; x5 x1 x4 x0
+
+; ----------
+       movq mm5, mm0 ;                                 ; 5 ; x5 x1 x4 x0
+       punpckldq mm0, mm0 ;                    ; x4 x0 x4 x0
+
+       movq mm4,   [TABLE+8] ; ; 4 ; w07 w05 w03 w01
+       punpckhwd mm2, mm1 ;                    ; 1 ; x7 x3 x6 x2
+
+       pmaddwd mm3, mm0 ;                              ; x4*w06+x0*w04 x4*w02+x0*w00
+       movq mm6, mm2 ;                         ; 6 ; x7 x3 x6 x2
+
+       movq mm1,   [TABLE+32] ;; 1 ; w22 w20 w18 w16
+       punpckldq mm2, mm2 ;                    ; x6 x2 x6 x2
+
+       pmaddwd mm4, mm2 ;                              ; x6*w07+x2*w05 x6*w03+x2*w01
+       punpckhdq mm5, mm5 ;                    ; x5 x1 x5 x1
+
+       pmaddwd mm0,   [TABLE+16] ;; x4*w14+x0*w12 x4*w10+x0*w08
+       punpckhdq mm6, mm6 ;                    ; x7 x3 x7 x3
+
+       movq mm7,   [TABLE+40] ;; 7 ; w23 w21 w19 w17
+       pmaddwd mm1, mm5 ;                              ; x5*w22+x1*w20 x5*w18+x1*w16
+
+       paddd mm3,   [round_inv_row];; +rounder
+       pmaddwd mm7, mm6 ;                              ; x7*w23+x3*w21 x7*w19+x3*w17
+
+       pmaddwd mm2,   [TABLE+24] ;; x6*w15+x2*w13 x6*w11+x2*w09
+       paddd mm3, mm4 ;                                ; 4 ; a1=sum(even1) a0=sum(even0)
+
+       pmaddwd mm5,   [TABLE+48] ;; x5*w30+x1*w28 x5*w26+x1*w24
+       movq mm4, mm3 ;                         ; 4 ; a1 a0
+
+       pmaddwd mm6,   [TABLE+56] ;; x7*w31+x3*w29 x7*w27+x3*w25
+       paddd mm1, mm7 ;                                ; 7 ; b1=sum(odd1) b0=sum(odd0)
+
+       paddd mm0,   [round_inv_row];; +rounder
+       psubd mm3, mm1 ;                                ; a1-b1 a0-b0
+
+       psrad mm3, SHIFT_INV_ROW ;              ; y6=a1-b1 y7=a0-b0
+       paddd mm1, mm4 ;                                ; 4 ; a1+b1 a0+b0
+
+       paddd mm0, mm2 ;                                ; 2 ; a3=sum(even3) a2=sum(even2)
+       psrad mm1, SHIFT_INV_ROW ;              ; y1=a1+b1 y0=a0+b0
+
+       paddd mm5, mm6 ;                                ; 6 ; b3=sum(odd3) b2=sum(odd2)
+       movq mm4, mm0 ;                         ; 4 ; a3 a2
+
+       paddd mm0, mm5 ;                                ; a3+b3 a2+b2
+       psubd mm4, mm5 ;                                ; 5 ; a3-b3 a2-b2
+
+       add INP, 16;                                    ; increment INPUT pointer -> row 1
+       psrad mm4, SHIFT_INV_ROW ;              ; y4=a3-b3 y5=a2-b2
+
+;      add TABLE, 0;                                   ;  TABLE += 64 -> row 1
+       psrad mm0, SHIFT_INV_ROW ;              ; y3=a3+b3 y2=a2+b2
+
+;      movq mm2,   [INP] ;             ; row+1; 0;  x3 x2 x1 x0
+       packssdw mm4, mm3 ;                             ; 3 ; y6 y7 y4 y5
+
+       packssdw mm1, mm0 ;                             ; 0 ; y3 y2 y1 y0
+       movq mm7, mm4 ;                         ; 7 ; y6 y7 y4 y5
+
+;      movq mm0, mm2 ;                                 ; row+1;  2 ; x3 x2 x1 x0
+       psrld mm4, 16 ;                                 ; 0 y6 0 y4
+
+       movq   [OUT], mm1 ;     ; 1 ; save y3 y2 y1 y0
+       pslld mm7, 16 ;                                 ; y7 0 y5 0
+
+;      movq mm1,   [INP+8] ;   ; row+1;  1 ; x7 x6 x5 x4
+       por mm7, mm4 ;                                  ; 4 ; y7 y6 y5 y4
+
+       movq mm3,   [TABLE] ;   ; 3 ; w06 w04 w02 w00
+;       punpcklwd mm0, mm1 ;                   ; row+1;  x5 x1 x4 x0
+
+   ; begin processing row 1
+       movq   [OUT+8], mm7 ;   ; 7 ; save y7 y6 y5 y4
+       add edi, 0x01;
+
+       add OUT, 16;                                    ; increment OUTPUT pointer -> row 1
+       cmp edi, 0x08;
+       jl near lpa;            ; end for ( x = 0; x < 8; ++x )  
+
+       ; done with the iDCT row-transformation
+
+       ; now we have to transpose the output 8x8 matrix
+       ; 8x8 (OUT) -> 8x8't' (IN)
+       ; the transposition is implemented as 4 sub-operations.
+       ; 1) transpose upper-left quad
+       ; 2) transpose lower-right quad
+       ; 3) transpose lower-left quad
+       ; 4) transpose upper-right quad
+
+       ; mm0 = 1st row [ A B C D ] row1
+       ; mm1 = 2nd row [ E F G H ] 2
+       ; mm2 = 3rd row [ I J K L ] 3
+       ; mm3 = 4th row [ M N O P ] 4
+
+                       ; 1) transpose upper-left quad
+;      lea OUT,   [qwTemp];
+       mov OUT,    [ebp+12];
+
+       movq mm0,   [OUT + ROW_STRIDE * 0 ]
+
+       movq mm1,   [OUT + ROW_STRIDE * 1 ]
+       movq mm4, mm0;  ; mm4 = copy of row1[A B C D]
+       
+       movq mm2,   [OUT + ROW_STRIDE * 2 ]
+       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+       
+       movq mm3,   [OUT + ROW_STRIDE * 3]
+       punpckhwd mm4, mm1; ; mm4 = [ 2 6 3 7]
+
+       movq mm6, mm2;
+       punpcklwd mm2, mm3;     ; mm2 = [ 8 12 9 13]
+
+       punpckhwd mm6, mm3;     ; mm6 = 10 14 11 15]
+       movq mm1, mm0;  ; mm1 = [ 0 4 1 5]
+
+       mov INP,   [ebp+8];     ; load input address
+       punpckldq mm0, mm2;     ; final result mm0 = row1 [0 4 8 12]
+
+       movq mm3, mm4;  ; mm3 = [ 2 6 3 7]
+       punpckhdq mm1, mm2; ; mm1 = final result mm1 = row2 [1 5 9 13]
+
+       movq   [ INP + ROW_STRIDE * 0 ], mm0; ; store row 1
+       punpckldq mm4, mm6; ; final result mm4 = row3 [2 6 10 14]
+
+               ; begin reading next quadrant (lower-right)
+       movq mm0,   [OUT + ROW_STRIDE*4 + 8]; 
+       punpckhdq mm3, mm6; ; final result mm3 = row4 [3 7 11 15]
+
+       movq   [ INP +ROW_STRIDE * 2], mm4; ; store row 3
+       movq mm4, mm0;  ; mm4 = copy of row1[A B C D]
+
+       movq   [ INP +ROW_STRIDE * 1], mm1; ; store row 2
+
+       movq mm1,   [OUT + ROW_STRIDE*5 + 8]
+
+       movq   [ INP +ROW_STRIDE * 3], mm3; ; store row 4
+       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+
+                       ; 2) transpose lower-right quadrant
+
+;      movq mm0,   [OUT + ROW_STRIDE*4 + 8]
+
+;      movq mm1,   [OUT + ROW_STRIDE*5 + 8]
+;       movq mm4, mm0; ; mm4 = copy of row1[A B C D]
+       
+       movq mm2,   [OUT + ROW_STRIDE*6 + 8]
+;       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+       punpckhwd mm4, mm1; ; mm4 = [ 2 6 3 7]
+       
+       movq mm3,   [OUT + ROW_STRIDE*7 + 8]
+       movq mm6, mm2;
+
+       punpcklwd mm2, mm3;     ; mm2 = [ 8 12 9 13]
+       movq mm1, mm0;  ; mm1 = [ 0 4 1 5]
+
+       punpckhwd mm6, mm3;     ; mm6 = 10 14 11 15]
+       movq mm3, mm4;  ; mm3 = [ 2 6 3 7]
+
+       punpckldq mm0, mm2;     ; final result mm0 = row1 [0 4 8 12]
+
+       punpckhdq mm1, mm2; ; mm1 = final result mm1 = row2 [1 5 9 13]
+       ; ; slot
+
+       movq   [ INP + ROW_STRIDE*4 + 8], mm0; ; store row 1
+        punpckldq mm4, mm6; ; final result mm4 = row3 [2 6 10 14]
+
+       movq mm0,   [OUT + ROW_STRIDE * 4 ]
+       punpckhdq mm3, mm6; ; final result mm3 = row4 [3 7 11 15]
+       movq   [ INP +ROW_STRIDE*6 + 8], mm4; ; store row 3
+        movq mm4, mm0; ; mm4 = copy of row1[A B C D]
+       movq   [ INP +ROW_STRIDE*5 + 8], mm1; ; store row 2
+        ; ;  slot
+       movq mm1,   [OUT + ROW_STRIDE * 5 ]
+        ; ;  slot
+
+       movq   [ INP +ROW_STRIDE*7 + 8], mm3; ; store row 4
+       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+
+  ; 3) transpose lower-left
+;      movq mm0,   [OUT + ROW_STRIDE * 4 ]
+
+;      movq mm1,   [OUT + ROW_STRIDE * 5 ]
+;       movq mm4, mm0; ; mm4 = copy of row1[A B C D]
+
+       movq mm2,   [OUT + ROW_STRIDE * 6 ]
+;       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+       punpckhwd mm4, mm1; ; mm4 = [ 2 6 3 7]
+
+       movq mm3,   [OUT + ROW_STRIDE * 7 ]
+       movq mm6, mm2;
+
+       punpcklwd mm2, mm3;     ; mm2 = [ 8 12 9 13]
+       movq mm1, mm0;  ; mm1 = [ 0 4 1 5]
+
+       punpckhwd mm6, mm3;     ; mm6 = 10 14 11 15]
+        movq mm3, mm4; ; mm3 = [ 2 6 3 7]
+
+       punpckldq mm0, mm2;     ; final result mm0 = row1 [0 4 8 12]
+
+       punpckhdq mm1, mm2; ; mm1 = final result mm1 = row2 [1 5 9 13]
+        ; ; slot
+
+       movq   [ INP + ROW_STRIDE * 0 + 8 ], mm0; ; store row 1
+        punpckldq mm4, mm6; ; final result mm4 = row3 [2 6 10 14]
+
+; begin reading next quadrant (upper-right)
+       movq mm0,   [OUT + ROW_STRIDE*0 + 8];
+       punpckhdq mm3, mm6; ; final result mm3 = row4 [3 7 11 15]
+
+       movq   [ INP +ROW_STRIDE * 2 + 8], mm4; ; store row 3
+       movq mm4, mm0;  ; mm4 = copy of row1[A B C D]
+
+       movq   [ INP +ROW_STRIDE * 1 + 8 ], mm1; ; store row 2
+       movq mm1,   [OUT + ROW_STRIDE*1 + 8]
+
+       movq   [ INP +ROW_STRIDE * 3 + 8], mm3; ; store row 4
+       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+
+
+       ; 2) transpose lower-right quadrant
+
+;      movq mm0,   [OUT + ROW_STRIDE*4 + 8]
+
+;      movq mm1,   [OUT + ROW_STRIDE*5 + 8]
+;       movq mm4, mm0; ; mm4 = copy of row1[A B C D]
+
+       movq mm2,   [OUT + ROW_STRIDE*2 + 8]
+;       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+        punpckhwd mm4, mm1; ; mm4 = [ 2 6 3 7]
+
+       movq mm3,   [OUT + ROW_STRIDE*3 + 8]
+       movq mm6, mm2;
+
+       punpcklwd mm2, mm3;     ; mm2 = [ 8 12 9 13]
+       movq mm1, mm0;  ; mm1 = [ 0 4 1 5]
+
+       punpckhwd mm6, mm3;     ; mm6 = 10 14 11 15]
+       movq mm3, mm4;  ; mm3 = [ 2 6 3 7]
+
+       punpckldq mm0, mm2;     ; final result mm0 = row1 [0 4 8 12]
+
+       punpckhdq mm1, mm2; ; mm1 = final result mm1 = row2 [1 5 9 13]
+       ; ; slot
+
+       movq   [ INP + ROW_STRIDE*4 ], mm0; ; store row 1
+       punpckldq mm4, mm6; ; final result mm4 = row3 [2 6 10 14]
+
+       movq   [ INP +ROW_STRIDE*5 ], mm1; ; store row 2
+       punpckhdq mm3, mm6; ; final result mm3 = row4 [3 7 11 15]
+
+       movq   [ INP +ROW_STRIDE*6 ], mm4; ; store row 3
+        ; ;  slot
+
+       movq   [ INP +ROW_STRIDE*7 ], mm3; ; store row 4
+
+       ; Conceptually this is the column transform.
+       ; Actually, the matrix is transformed
+       ; row by row.  This function is identical to idct_mmx32_rows(),
+       ; except for the SHIFT amount and ROUND_INV amount.
+
+       ; this subroutine performs two operations
+       ; 1) iDCT row transform
+       ;               for( i = 0; i < 8; ++ i)
+       ;                       DCT_8_INV_ROW_1( blk[i*8], qwTemp[i] );
+       ;
+       ; 2) transpose the matrix (which was stored in qwTemp[])
+       ;        qwTemp[] -> [8x8 matrix transpose] -> blk[]
+
+
+       mov INP,   [ebp+8];             ; ; row 0
+       mov edi, 0x00;  ; x = 0
+       lea TABLE,   [idct_tab_01234567]; ; row 0
+;      lea OUT,   [qwTemp];
+       mov OUT,    [ebp+12];
+;       mov OUT, INP;  ; algorithm writes data in-place  -> row 0
+
+       lea round_inv_col,   [idct_r_inv_col]
+    jmp acc_idct_colloop1
+                       
+       ; for ( x = 0; x < 8; ++x )  ; transform one row per iteration
+align 32               
+acc_idct_colloop1:
+
+       movq mm0,   [INP] ;             ; 0 ; x3 x2 x1 x0
+
+       movq mm1,   [INP+8] ;   ; 1 ; x7 x6 x5 x4
+       movq mm2, mm0 ;                         ; 2 ; x3 x2 x1 x0
+
+       movq mm3,   [TABLE] ;   ; 3 ; w06 w04 w02 w00
+       punpcklwd mm0, mm1 ;                    ; x5 x1 x4 x0
+
+; ----------
+       movq mm5, mm0 ;                                 ; 5 ; x5 x1 x4 x0
+       punpckldq mm0, mm0 ;                    ; x4 x0 x4 x0
+
+       movq mm4,   [TABLE+8] ; ; 4 ; w07 w05 w03 w01
+       punpckhwd mm2, mm1 ;                    ; 1 ; x7 x3 x6 x2
+
+       pmaddwd mm3, mm0 ;                              ; x4*w06+x0*w04 x4*w02+x0*w00
+       movq mm6, mm2 ;                         ; 6 ; x7 x3 x6 x2
+
+       movq mm1,   [TABLE+32] ;; 1 ; w22 w20 w18 w16
+       punpckldq mm2, mm2 ;                    ; x6 x2 x6 x2
+
+       pmaddwd mm4, mm2 ;                              ; x6*w07+x2*w05 x6*w03+x2*w01
+       punpckhdq mm5, mm5 ;                    ; x5 x1 x5 x1
+
+       pmaddwd mm0,   [TABLE+16] ;; x4*w14+x0*w12 x4*w10+x0*w08
+       punpckhdq mm6, mm6 ;                    ; x7 x3 x7 x3
+
+       movq mm7,   [TABLE+40] ;; 7 ; w23 w21 w19 w17
+       pmaddwd mm1, mm5 ;                              ; x5*w22+x1*w20 x5*w18+x1*w16
+
+       paddd mm3,   [round_inv_col] ;; +rounder
+       pmaddwd mm7, mm6 ;                              ; x7*w23+x3*w21 x7*w19+x3*w17
+
+       pmaddwd mm2,   [TABLE+24] ;; x6*w15+x2*w13 x6*w11+x2*w09
+       paddd mm3, mm4 ;                                ; 4 ; a1=sum(even1) a0=sum(even0)
+
+       pmaddwd mm5,   [TABLE+48] ;; x5*w30+x1*w28 x5*w26+x1*w24
+       movq mm4, mm3 ;                         ; 4 ; a1 a0
+
+       pmaddwd mm6,   [TABLE+56] ;; x7*w31+x3*w29 x7*w27+x3*w25
+       paddd mm1, mm7 ;                                ; 7 ; b1=sum(odd1) b0=sum(odd0)
+
+       paddd mm0,   [round_inv_col] ;; +rounder
+       psubd mm3, mm1 ;                                ; a1-b1 a0-b0
+
+       psrad mm3, SHIFT_INV_COL;               ; y6=a1-b1 y7=a0-b0
+       paddd mm1, mm4 ;                                ; 4 ; a1+b1 a0+b0
+
+       paddd mm0, mm2 ;                                ; 2 ; a3=sum(even3) a2=sum(even2)
+       psrad mm1, SHIFT_INV_COL;               ; y1=a1+b1 y0=a0+b0
+
+       paddd mm5, mm6 ;                                ; 6 ; b3=sum(odd3) b2=sum(odd2)
+       movq mm4, mm0 ;                         ; 4 ; a3 a2
+
+       paddd mm0, mm5 ;                                ; a3+b3 a2+b2
+       psubd mm4, mm5 ;                                ; 5 ; a3-b3 a2-b2
+
+       add INP, 16;                                    ; increment INPUT pointer -> row 1
+       psrad mm4, SHIFT_INV_COL;               ; y4=a3-b3 y5=a2-b2
+
+       add TABLE, 0;                                   ;  TABLE += 64 -> row 1
+       psrad mm0, SHIFT_INV_COL;               ; y3=a3+b3 y2=a2+b2
+
+;      movq mm2,   [INP] ;             ; row+1; 0;  x3 x2 x1 x0
+       packssdw mm4, mm3 ;                             ; 3 ; y6 y7 y4 y5
+
+       packssdw mm1, mm0 ;                             ; 0 ; y3 y2 y1 y0
+       movq mm7, mm4 ;                         ; 7 ; y6 y7 y4 y5
+
+;      movq mm0, mm2 ;                                 ; row+1;  2 ; x3 x2 x1 x0
+;      por mm1,   dct_one_corr ;       ; correction y2 +0.5
+       psrld mm4, 16 ;                                 ; 0 y6 0 y4
+
+       movq   [OUT], mm1 ;     ; 1 ; save y3 y2 y1 y0
+       pslld mm7, 16 ;                                 ; y7 0 y5 0
+
+;      movq mm1,   [INP+8] ;   ; row+1;  1 ; x7 x6 x5 x4
+;      por mm7,   dct_one_corr ;       ; correction y2 +0.5
+       por mm7, mm4 ;                                  ; 4 ; y7 y6 y5 y4
+
+;      movq mm3,   [TABLE] ;   ; 3 ; w06 w04 w02 w00
+;       punpcklwd mm0, mm1 ;                   ; row+1;  x5 x1 x4 x0
+
+   ; begin processing row 1
+       movq   [OUT+8], mm7 ;   ; 7 ; save y7 y6 y5 y4
+       add edi, 0x01;
+
+       add OUT, 16;
+       cmp edi, 0x08;  ; compare x <> 8
+
+       jl near  acc_idct_colloop1;     ; end for ( x = 0; x < 8; ++x )  
+
+       ; done with the iDCT column-transformation
+
+               ; now we have to transpose the output 8x8 matrix
+               ; 8x8 (OUT) -> 8x8't' (IN)
+
+               ; the transposition is implemented as 4 sub-operations.
+       ; 1) transpose upper-left quad
+       ; 2) transpose lower-right quad
+       ; 3) transpose lower-left quad
+       ; 4) transpose upper-right quad
+
+
+       ; mm0 = 1st row [ A B C D ] row1
+       ; mm1 = 2nd row [ E F G H ] 2
+       ; mm2 = 3rd row [ I J K L ] 3
+       ; mm3 = 4th row [ M N O P ] 4
+
+       ; 1) transpose upper-left quad
+;      lea OUT,   [qwTemp];
+       mov OUT,    [ebp+12];
+
+       movq mm0,   [OUT + ROW_STRIDE * 0 ]
+
+       movq mm1,   [OUT + ROW_STRIDE * 1 ]
+       movq mm4, mm0;  ; mm4 = copy of row1[A B C D]
+       
+       movq mm2,   [OUT + ROW_STRIDE * 2 ]
+       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+       
+       movq mm3,   [OUT + ROW_STRIDE * 3]
+       punpckhwd mm4, mm1 ; mm4 = [ 2 6 3 7]
+
+       movq mm6, mm2
+       punpcklwd mm2, mm3      ; mm2 = [ 8 12 9 13]
+
+       punpckhwd mm6, mm3      ; mm6 = 10 14 11 15]
+       movq mm1, mm0   ; mm1 = [ 0 4 1 5]
+
+       mov INP,   [ebp+8]      ; load input address
+       punpckldq mm0, mm2      ; final result mm0 = row1 [0 4 8 12]
+
+       movq mm3, mm4;  ; mm3 = [ 2 6 3 7]
+       punpckhdq mm1, mm2; ; mm1 = final result mm1 = row2 [1 5 9 13]
+
+       movq   [ INP + ROW_STRIDE * 0 ], mm0; ; store row 1
+       punpckldq mm4, mm6; ; final result mm4 = row3 [2 6 10 14]
+
+; begin reading next quadrant (lower-right)
+       movq mm0,   [OUT + ROW_STRIDE*4 + 8]; 
+       punpckhdq mm3, mm6; ; final result mm3 = row4 [3 7 11 15]
+
+       movq   [ INP +ROW_STRIDE * 2], mm4; ; store row 3
+       movq mm4, mm0;  ; mm4 = copy of row1[A B C D]
+
+       movq   [ INP +ROW_STRIDE * 1], mm1; ; store row 2
+
+       movq mm1,   [OUT + ROW_STRIDE*5 + 8]
+
+       movq   [ INP +ROW_STRIDE * 3], mm3; ; store row 4
+       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+
+       ; 2) transpose lower-right quadrant
+
+;      movq mm0,   [OUT + ROW_STRIDE*4 + 8]
+
+;      movq mm1,   [OUT + ROW_STRIDE*5 + 8]
+;       movq mm4, mm0; ; mm4 = copy of row1[A B C D]
+       
+       movq mm2,   [OUT + ROW_STRIDE*6 + 8]
+;       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+        punpckhwd mm4, mm1; ; mm4 = [ 2 6 3 7]
+       
+       movq mm3,   [OUT + ROW_STRIDE*7 + 8]
+       movq mm6, mm2;
+
+       punpcklwd mm2, mm3;     ; mm2 = [ 8 12 9 13]
+       movq mm1, mm0;  ; mm1 = [ 0 4 1 5]
+
+       punpckhwd mm6, mm3;     ; mm6 = 10 14 11 15]
+       movq mm3, mm4;  ; mm3 = [ 2 6 3 7]
+
+       punpckldq mm0, mm2;     ; final result mm0 = row1 [0 4 8 12]
+
+       punpckhdq mm1, mm2; ; mm1 = final result mm1 = row2 [1 5 9 13]
+       ; ;  slot
+
+       movq   [ INP + ROW_STRIDE*4 + 8], mm0; ; store row 1
+       punpckldq mm4, mm6; ; final result mm4 = row3 [2 6 10 14]
+
+       movq mm0,   [OUT + ROW_STRIDE * 4 ]
+       punpckhdq mm3, mm6; ; final result mm3 = row4 [3 7 11 15]
+       movq   [ INP +ROW_STRIDE*6 + 8], mm4; ; store row 3
+       movq mm4, mm0;  ; mm4 = copy of row1[A B C D]
+
+       movq   [ INP +ROW_STRIDE*5 + 8], mm1; ; store row 2
+        ; ;  slot
+       movq mm1,   [OUT + ROW_STRIDE * 5 ]
+        ; ;  slot
+
+       movq   [ INP +ROW_STRIDE*7 + 8], mm3; ; store row 4
+       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+
+  ; 3) transpose lower-left
+;      movq mm0,   [OUT + ROW_STRIDE * 4 ]
+
+;      movq mm1,   [OUT + ROW_STRIDE * 5 ]
+;       movq mm4, mm0; ; mm4 = copy of row1[A B C D]
+       
+       movq mm2,   [OUT + ROW_STRIDE * 6 ]
+;       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+       punpckhwd mm4, mm1; ; mm4 = [ 2 6 3 7]
+       
+       movq mm3,   [OUT + ROW_STRIDE * 7 ]
+       movq mm6, mm2;
+
+       punpcklwd mm2, mm3;     ; mm2 = [ 8 12 9 13]
+       movq mm1, mm0;  ; mm1 = [ 0 4 1 5]
+
+       punpckhwd mm6, mm3;     ; mm6 = 10 14 11 15]
+       movq mm3, mm4;  ; mm3 = [ 2 6 3 7]
+
+       punpckldq mm0, mm2;     ; final result mm0 = row1 [0 4 8 12]
+
+       punpckhdq mm1, mm2; ; mm1 = final result mm1 = row2 [1 5 9 13]
+        ; ; slot
+
+       movq   [ INP + ROW_STRIDE * 0 + 8 ], mm0; ; store row 1
+       punpckldq mm4, mm6; ; final result mm4 = row3 [2 6 10 14]
+
+; begin reading next quadrant (upper-right)
+       movq mm0,   [OUT + ROW_STRIDE*0 + 8];
+       punpckhdq mm3, mm6; ; final result mm3 = row4 [3 7 11 15]
+
+       movq   [ INP +ROW_STRIDE * 2 + 8], mm4; ; store row 3
+       movq mm4, mm0;  ; mm4 = copy of row1[A B C D]
+
+       movq   [ INP +ROW_STRIDE * 1 + 8 ], mm1; ; store row 2
+       movq mm1,   [OUT + ROW_STRIDE*1 + 8]
+
+       movq   [ INP +ROW_STRIDE * 3 + 8], mm3; ; store row 4
+       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+
+
+       ; 2) transpose lower-right quadrant
+
+;      movq mm0,   [OUT + ROW_STRIDE*4 + 8]
+
+;      movq mm1,   [OUT + ROW_STRIDE*5 + 8]
+;       movq mm4, mm0; ; mm4 = copy of row1[A B C D]
+
+       movq mm2,   [OUT + ROW_STRIDE*2 + 8]
+;       punpcklwd mm0, mm1; ; mm0 = [ 0 4 1 5]
+       punpckhwd mm4, mm1; ; mm4 = [ 2 6 3 7]
+
+       movq mm3,   [OUT + ROW_STRIDE*3 + 8]
+       movq mm6, mm2;
+
+       punpcklwd mm2, mm3;     ; mm2 = [ 8 12 9 13]
+       movq mm1, mm0;  ; mm1 = [ 0 4 1 5]
+
+       punpckhwd mm6, mm3;     ; mm6 = 10 14 11 15]
+       movq mm3, mm4;  ; mm3 = [ 2 6 3 7]
+
+       punpckldq mm0, mm2;     ; final result mm0 = row1 [0 4 8 12]
+
+       punpckhdq mm1, mm2; ; mm1 = final result mm1 = row2 [1 5 9 13]
+       ; ;  slot
+
+       movq  [ INP + ROW_STRIDE*4 ], mm0; ; store row 1
+       punpckldq mm4, mm6; ; final result mm4 = row3 [2 6 10 14]
+
+       movq  [ INP +ROW_STRIDE*5 ], mm1; ; store row 2
+       punpckhdq mm3, mm6; ; final result mm3 = row4 [3 7 11 15]
+
+       movq  [ INP +ROW_STRIDE*6 ], mm4; ; store row 3
+        ; ;  slot
+
+       movq  [ INP +ROW_STRIDE*7 ], mm3; ; store row 4
+
+       pop edi
+       pop edx
+       pop ecx
+       pop ebx
+
+       pop ebp                 ; restore frame pointer
+
+       emms
+       ret
diff --git a/mpeg2enc/mblock_sad_mmx.s b/mpeg2enc/mblock_sad_mmx.s
new file mode 100644 (file)
index 0000000..a58c580
--- /dev/null
@@ -0,0 +1,1093 @@
+;;; 
+;;;  mblock_sad_mmxe.s:  
+;;; 
+;;; Enhanced MMX optimized Sum Absolute Differences routines for macroblocks
+;;; (interpolated, 1-pel, 2*2 sub-sampled pel and 4*4 sub-sampled pel)
+;
+;  dist1_* Original Copyright (C) 2000 Chris Atenasio <chris@crud.net>
+;  Enhancements and rest Copyright (C) 2000 Andrew Stevens <as@comlab.ox.ac.uk>
+
+;
+;  This program is free software; you can redistribute it and/or
+;  modify it under the terms of the GNU General Public License
+;  as published by the Free Software Foundation; either version 2
+;  of the License, or (at your option) any later version.
+;
+;  This program is distributed in the hope that it will be useful,
+;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;  GNU General Public License for more details.
+;
+;  You should have received a copy of the GNU General Public License
+;  along with this program; if not, write to the Free Software
+;  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+;
+;
+;
+
+
+global dist1_00_mmx
+
+; int dist1_mmx(unsigned char *blk1,unsigned char *blk2,int lx,int h, int distlim);
+; N.b. distlim is *ignored* as testing for it is more expensive than the
+; occasional saving by aborting the computionation early...
+; esi = p1 (init:              blk1)
+; edi = p2 (init:              blk2)
+; ebx = distlim  
+; ecx = rowsleft (init:         h)
+; edx = lx;
+
+; mm0 = distance accumulators (4 words)
+; mm1 = temp 
+; mm2 = temp 
+; mm3 = temp
+; mm4 = temp
+; mm5 = temp 
+; mm6 = 0
+; mm7 = temp
+
+
+align 32
+dist1_00_mmx:
+       push ebp                ; save frame pointer
+       mov ebp, esp
+
+       push ebx                ; Saves registers (called saves convention in
+       push ecx                ; x86 GCC it seems)
+       push edx                ; 
+       push esi
+       push edi
+               
+       pxor mm0, mm0                           ; zero acculumators
+       pxor mm6, mm6
+       mov esi, [ebp+8]                        ; get p1
+       mov edi, [ebp+12]                       ; get p2
+       mov edx, [ebp+16]                       ; get lx
+       mov  ecx, [ebp+20]                      ; get rowsleft
+       ;mov ebx, [ebp+24]              ; distlim
+       jmp nextrowmm00
+align 32
+nextrowmm00:
+       movq mm4, [esi]         ; load first 8 bytes of p1 row 
+       movq mm5, [edi]         ; load first 8 bytes of p2 row
+               
+       movq mm7, mm4       ; mm5 = abs(mm4-mm5)
+       psubusb mm7, mm5
+       psubusb mm5, mm4
+       paddb   mm5, mm7
+
+       ;;  Add the abs(mm4-mm5) bytes to the accumulators
+       movq mm2, [esi+8]               ; load second 8 bytes of p1 row (interleaved)
+       movq  mm7,mm5                           ; mm7 := [i :   B0..3, mm1]W
+       punpcklbw mm7,mm6
+       movq mm3, [edi+8]               ; load second 8 bytes of p2 row (interleaved)
+       paddw mm0, mm7
+       punpckhbw mm5,mm6
+       paddw mm0, mm5
+
+               ;; This is logically where the mm2, mm3 loads would go...
+               
+       movq mm7, mm2       ; mm3 = abs(mm2-mm3)
+       psubusb mm7, mm3
+       psubusb mm3, mm2
+       paddb   mm3, mm7
+
+       ;;  Add the abs(mm4-mm5) bytes to the accumulators
+       movq  mm7,mm3                           ; mm7 := [i :   B0..3, mm1]W
+       punpcklbw mm7,mm6
+       punpckhbw mm3,mm6
+       paddw mm0, mm7
+       
+       add esi, edx            ; update pointer to next row
+       add edi, edx            ; ditto 
+
+       paddw mm0, mm3
+
+
+
+       sub  ecx,1
+       jnz near nextrowmm00
+               
+returnmm00:    
+
+               ;; Sum the Accumulators
+       movq  mm5, mm0                          ; mm5 := [W0+W2,W1+W3, mm0
+       psrlq mm5, 32
+       movq  mm4, mm0
+       paddw mm4, mm5
+
+       movq  mm7, mm4              ; mm6 := [W0+W2+W1+W3, mm0]
+       psrlq mm7, 16
+       paddw mm4, mm7
+       movd eax, mm4           ; store return value
+       and  eax, 0xffff
+
+       pop edi
+       pop esi 
+       pop edx 
+       pop ecx 
+       pop ebx 
+
+       pop ebp 
+
+       emms                    ; clear mmx registers
+       ret     
+;
+;;;  dist1_01_mmx.s:  mmx1 optimised 7bit*8 word absolute difference sum
+;;;     We're reduce to seven bits as otherwise we also have to mess
+;;;     horribly with carries and signed only comparisons make the code
+;;;     simply enormous (and probably barely faster than a simple loop).
+;;;     Since signals with a bona-fide 8bit res will be rare we simply
+;;;     take the precision hit...
+;;;     Actually we don't worry about carries from the low-order bits
+;;;     either so 1/4 of the time we'll be 1 too low...
+;;; 
+;  Copyright (C) 2000 Andrew Stevens <as@comlab.ox.ac.uk>
+
+;
+;  This program is free software; you can redistribute it and/or
+;  modify it under the terms of the GNU General Public License
+;  as published by the Free Software Foundation; either version 2
+;  of the License, or (at your option) any later version.
+;
+;  This program is distributed in the hope that it will be useful,
+;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;  GNU General Public License for more details.
+;
+;  You should have received a copy of the GNU General Public License
+;  along with this program; if not, write to the Free Software
+;  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+;
+;
+;
+
+
+global dist1_01_mmx
+
+; int dist1_01_mmx(unsigned char *p1,unsigned char *p2,int lx,int h);
+
+; esi = p1 (init:              blk1)
+; edi = p2 (init:              blk2)
+; ecx = rowsleft (init:         h)
+; edx = lx;
+
+; mm0 = distance accumulators (4 words)
+; mm1 = bytes p2
+; mm2 = bytes p1
+; mm3 = bytes p1+1
+; mm4 = temp 4 bytes in words interpolating p1, p1+1
+; mm5 = temp 4 bytes in words from p2
+; mm6 = temp comparison bit mask p1,p2
+; mm7 = temp comparison bit mask p2,p1
+
+
+align 32
+dist1_01_mmx:
+       push ebp                ; save stack pointer
+       mov ebp, esp    ; so that we can do this
+
+       push ebx                ; Saves registers (called saves convention in
+       push ecx                ; x86 GCC it seems)
+       push edx                ; 
+       push esi
+       push edi
+               
+       pxor mm0, mm0                           ; zero acculumators
+
+       mov esi, [ebp+8]                        ; get p1
+       mov edi, [ebp+12]                       ; get p2
+       mov edx, [ebp+16]                       ; get lx
+       mov ecx, [ebp+20]                       ; rowsleft := h
+       jmp nextrowmm01                                 ; snap to it
+align 32
+nextrowmm01:
+
+               ;; 
+               ;; First 8 bytes of row
+               ;; 
+               
+               ;; First 4 bytes of 8
+
+       movq mm4, [esi]             ; mm4 := first 4 bytes p1
+       pxor mm7, mm7
+       movq mm2, mm4                           ;  mm2 records all 8 bytes
+       punpcklbw mm4, mm7            ;  First 4 bytes p1 in Words...
+       
+       movq mm6, [esi+1]                       ;  mm6 := first 4 bytes p1+1
+       movq mm3, mm6               ;  mm3 records all 8 bytes
+       punpcklbw mm6, mm7
+       paddw mm4, mm6              ;  mm4 := First 4 bytes interpolated in words
+       psrlw mm4, 1
+               
+       movq mm5, [edi]                         ; mm5:=first 4 bytes of p2 in words
+       movq mm1, mm5
+       punpcklbw mm5, mm7
+                       
+       movq  mm7,mm4
+       pcmpgtw mm7,mm5         ; mm7 := [i : W0..3,mm4>mm5]
+
+       movq  mm6,mm4           ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
+       psubw mm6,mm5
+       pand  mm6, mm7
+
+       paddw mm0, mm6                          ; Add to accumulator
+
+       movq  mm6,mm5       ; mm6 := [i : W0..3,mm5>mm4]
+       pcmpgtw mm6,mm4     
+       psubw mm5,mm4           ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
+       pand  mm5, mm6          
+
+       paddw mm0, mm5                          ; Add to accumulator
+
+               ;; Second 4 bytes of 8
+       
+       movq mm4, mm2               ; mm4 := Second 4 bytes p1 in words
+       pxor  mm7, mm7
+       punpckhbw mm4, mm7                      
+       movq mm6, mm3                   ; mm6 := Second 4 bytes p1+1 in words  
+       punpckhbw mm6, mm7
+               
+       paddw mm4, mm6          ;  mm4 := First 4 Interpolated bytes in words
+       psrlw mm4, 1
+
+       movq mm5, mm1                   ; mm5:= second 4 bytes of p2 in words
+       punpckhbw mm5, mm7
+                       
+       movq  mm7,mm4
+       pcmpgtw mm7,mm5         ; mm7 := [i : W0..3,mm4>mm5]
+
+       movq  mm6,mm4           ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
+       psubw mm6,mm5
+       pand  mm6, mm7
+
+       paddw mm0, mm6                          ; Add to accumulator
+
+       movq  mm6,mm5       ; mm6 := [i : W0..3,mm5>mm4]
+       pcmpgtw mm6,mm4     
+       psubw mm5,mm4           ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
+       pand  mm5, mm6          
+
+       paddw mm0, mm5                          ; Add to accumulator
+
+
+               ;;
+               ;; Second 8 bytes of row
+               ;; 
+               ;; First 4 bytes of 8
+
+       movq mm4, [esi+8]             ; mm4 := first 4 bytes p1+8
+       pxor mm7, mm7
+       movq mm2, mm4                           ;  mm2 records all 8 bytes
+       punpcklbw mm4, mm7            ;  First 4 bytes p1 in Words...
+       
+       movq mm6, [esi+9]                       ;  mm6 := first 4 bytes p1+9
+       movq mm3, mm6               ;  mm3 records all 8 bytes
+       punpcklbw mm6, mm7
+       paddw mm4, mm6              ;  mm4 := First 4 bytes interpolated in words
+       psrlw mm4, 1
+               
+       movq mm5, [edi+8]                               ; mm5:=first 4 bytes of p2+8 in words
+       movq mm1, mm5
+       punpcklbw mm5, mm7
+                       
+       movq  mm7,mm4
+       pcmpgtw mm7,mm5         ; mm7 := [i : W0..3,mm4>mm5]
+
+       movq  mm6,mm4           ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
+       psubw mm6,mm5
+       pand  mm6, mm7
+
+       paddw mm0, mm6                          ; Add to accumulator
+
+       movq  mm6,mm5       ; mm6 := [i : W0..3,mm5>mm4]
+       pcmpgtw mm6,mm4     
+       psubw mm5,mm4           ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
+       pand  mm5, mm6          
+
+       paddw mm0, mm5                          ; Add to accumulator
+
+               ;; Second 4 bytes of 8
+       
+       movq mm4, mm2               ; mm4 := Second 4 bytes p1 in words
+       pxor  mm7, mm7
+       punpckhbw mm4, mm7                      
+       movq mm6, mm3                   ; mm6 := Second 4 bytes p1+1 in words  
+       punpckhbw mm6, mm7
+               
+       paddw mm4, mm6          ;  mm4 := First 4 Interpolated bytes in words
+       psrlw mm4, 1
+
+       movq mm5, mm1                   ; mm5:= second 4 bytes of p2 in words
+       punpckhbw mm5, mm7
+                       
+       movq  mm7,mm4
+       pcmpgtw mm7,mm5         ; mm7 := [i : W0..3,mm4>mm5]
+
+       movq  mm6,mm4           ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
+       psubw mm6,mm5
+       pand  mm6, mm7
+
+       paddw mm0, mm6                          ; Add to accumulator
+
+       movq  mm6,mm5       ; mm6 := [i : W0..3,mm5>mm4]
+       pcmpgtw mm6,mm4     
+       psubw mm5,mm4           ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
+       pand  mm5, mm6          
+
+       paddw mm0, mm5                          ; Add to accumulator
+
+
+               ;;
+               ;;      Loop termination condition... and stepping
+               ;;              
+
+       add esi, edx            ; update pointer to next row
+       add edi, edx            ; ditto
+                       
+       sub  ecx,1
+       test ecx, ecx           ; check rowsleft
+       jnz near nextrowmm01
+               
+
+               ;; Sum the Accumulators
+       movq  mm4, mm0
+       psrlq mm4, 32
+       paddw mm0, mm4
+       movq  mm6, mm0
+       psrlq mm6, 16
+       paddw mm0, mm6
+       movd eax, mm0           ; store return value
+       and  eax, 0xffff
+
+       pop edi
+       pop esi 
+       pop edx                 
+       pop ecx                 
+       pop ebx                 
+
+       pop ebp                 ; restore stack pointer
+
+       emms                    ; clear mmx registers
+       ret                     ; we now return you to your regular programming
+;
+;;;  dist1_01_mmx.s:  mmx1 optimised 7bit*8 word absolute difference sum
+;;;     We're reduce to seven bits as otherwise we also have to mess
+;;;     horribly with carries and signed only comparisons make the code
+;;;     simply enormous (and probably barely faster than a simple loop).
+;;;     Since signals with a bona-fide 8bit res will be rare we simply
+;;;     take the precision hit...
+;;;     Actually we don't worry about carries from the low-order bits
+;;;     either so 1/4 of the time we'll be 1 too low...
+;;; 
+;  Copyright (C) 2000 Andrew Stevens <as@comlab.ox.ac.uk>
+
+;
+;  This program is free software; you can redistribute it and/or
+;  modify it under the terms of the GNU General Public License
+;  as published by the Free Software Foundation; either version 2
+;  of the License, or (at your option) any later version.
+;
+;  This program is distributed in the hope that it will be useful,
+;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;  GNU General Public License for more details.
+;
+;  You should have received a copy of the GNU General Public License
+;  along with this program; if not, write to the Free Software
+;  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+;
+;
+;
+
+
+global dist1_10_mmx
+
+; int dist1_10_mmx(unsigned char *p1,unsigned char *p2,int lx,int h);
+
+; esi = p1 (init:              blk1)
+; edi = p2 (init:              blk2)
+; ebx = p1+lx
+; ecx = rowsleft (init:         h)
+; edx = lx;
+
+; mm0 = distance accumulators (4 words)
+; mm1 = bytes p2
+; mm2 = bytes p1
+; mm3 = bytes p1+1
+; mm4 = temp 4 bytes in words interpolating p1, p1+1
+; mm5 = temp 4 bytes in words from p2
+; mm6 = temp comparison bit mask p1,p2
+; mm7 = temp comparison bit mask p2,p1
+
+
+align 32
+dist1_10_mmx:
+       push ebp                ; save stack pointer
+       mov ebp, esp    ; so that we can do this
+
+       push ebx                ; Saves registers (called saves convention in
+       push ecx                ; x86 GCC it seems)
+       push edx                ; 
+       push esi
+       push edi
+               
+       pxor mm0, mm0                           ; zero acculumators
+
+       mov esi, [ebp+8]                        ; get p1
+       mov edi, [ebp+12]                       ; get p2
+       mov edx, [ebp+16]                       ; get lx
+       mov ecx, [ebp+20]                       ; rowsleft := h
+       mov ebx, esi
+    add ebx, edx               
+       jmp nextrowmm10                                 ; snap to it
+align 32
+nextrowmm10:
+
+               ;; 
+               ;; First 8 bytes of row
+               ;; 
+               
+               ;; First 4 bytes of 8
+
+       movq mm4, [esi]             ; mm4 := first 4 bytes p1
+       pxor mm7, mm7
+       movq mm2, mm4                           ;  mm2 records all 8 bytes
+       punpcklbw mm4, mm7            ;  First 4 bytes p1 in Words...
+       
+       movq mm6, [ebx]                     ;  mm6 := first 4 bytes p1+lx
+       movq mm3, mm6               ;  mm3 records all 8 bytes
+       punpcklbw mm6, mm7
+       paddw mm4, mm6              ;  mm4 := First 4 bytes interpolated in words
+       psrlw mm4, 1
+               
+       movq mm5, [edi]                         ; mm5:=first 4 bytes of p2 in words
+       movq mm1, mm5
+       punpcklbw mm5, mm7
+                       
+       movq  mm7,mm4
+       pcmpgtw mm7,mm5         ; mm7 := [i : W0..3,mm4>mm5]
+
+       movq  mm6,mm4           ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
+       psubw mm6,mm5
+       pand  mm6, mm7
+
+       paddw mm0, mm6                          ; Add to accumulator
+
+       movq  mm6,mm5       ; mm6 := [i : W0..3,mm5>mm4]
+       pcmpgtw mm6,mm4     
+       psubw mm5,mm4           ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
+       pand  mm5, mm6          
+
+       paddw mm0, mm5                          ; Add to accumulator
+
+               ;; Second 4 bytes of 8
+       
+       movq mm4, mm2               ; mm4 := Second 4 bytes p1 in words
+       pxor  mm7, mm7
+       punpckhbw mm4, mm7                      
+       movq mm6, mm3                   ; mm6 := Second 4 bytes p1+1 in words  
+       punpckhbw mm6, mm7
+               
+       paddw mm4, mm6          ;  mm4 := First 4 Interpolated bytes in words
+       psrlw mm4, 1
+
+       movq mm5, mm1                   ; mm5:= second 4 bytes of p2 in words
+       punpckhbw mm5, mm7
+                       
+       movq  mm7,mm4
+       pcmpgtw mm7,mm5         ; mm7 := [i : W0..3,mm4>mm5]
+
+       movq  mm6,mm4           ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
+       psubw mm6,mm5
+       pand  mm6, mm7
+
+       paddw mm0, mm6                          ; Add to accumulator
+
+       movq  mm6,mm5       ; mm6 := [i : W0..3,mm5>mm4]
+       pcmpgtw mm6,mm4     
+       psubw mm5,mm4           ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
+       pand  mm5, mm6          
+
+       paddw mm0, mm5                          ; Add to accumulator
+
+
+               ;;
+               ;; Second 8 bytes of row
+               ;; 
+               ;; First 4 bytes of 8
+
+       movq mm4, [esi+8]             ; mm4 := first 4 bytes p1+8
+       pxor mm7, mm7
+       movq mm2, mm4                           ;  mm2 records all 8 bytes
+       punpcklbw mm4, mm7            ;  First 4 bytes p1 in Words...
+       
+       movq mm6, [ebx+8]                       ;  mm6 := first 4 bytes p1+lx+8
+       movq mm3, mm6               ;  mm3 records all 8 bytes
+       punpcklbw mm6, mm7
+       paddw mm4, mm6              ;  mm4 := First 4 bytes interpolated in words
+       psrlw mm4, 1
+               
+       movq mm5, [edi+8]                               ; mm5:=first 4 bytes of p2+8 in words
+       movq mm1, mm5
+       punpcklbw mm5, mm7
+                       
+       movq  mm7,mm4
+       pcmpgtw mm7,mm5         ; mm7 := [i : W0..3,mm4>mm5]
+
+       movq  mm6,mm4           ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
+       psubw mm6,mm5
+       pand  mm6, mm7
+
+       paddw mm0, mm6                          ; Add to accumulator
+
+       movq  mm6,mm5       ; mm6 := [i : W0..3,mm5>mm4]
+       pcmpgtw mm6,mm4     
+       psubw mm5,mm4           ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
+       pand  mm5, mm6          
+
+       paddw mm0, mm5                          ; Add to accumulator
+
+               ;; Second 4 bytes of 8
+       
+       movq mm4, mm2               ; mm4 := Second 4 bytes p1 in words
+       pxor  mm7, mm7
+       punpckhbw mm4, mm7                      
+       movq mm6, mm3                   ; mm6 := Second 4 bytes p1+1 in words  
+       punpckhbw mm6, mm7
+               
+       paddw mm4, mm6          ;  mm4 := First 4 Interpolated bytes in words
+       psrlw mm4, 1
+
+       movq mm5, mm1                   ; mm5:= second 4 bytes of p2 in words
+       punpckhbw mm5, mm7
+                       
+       movq  mm7,mm4
+       pcmpgtw mm7,mm5         ; mm7 := [i : W0..3,mm4>mm5]
+
+       movq  mm6,mm4           ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
+       psubw mm6,mm5
+       pand  mm6, mm7
+
+       paddw mm0, mm6                          ; Add to accumulator
+
+       movq  mm6,mm5       ; mm6 := [i : W0..3,mm5>mm4]
+       pcmpgtw mm6,mm4     
+       psubw mm5,mm4           ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
+       pand  mm5, mm6          
+
+       paddw mm0, mm5                          ; Add to accumulator
+
+
+               ;;
+               ;;      Loop termination condition... and stepping
+               ;;              
+
+       add esi, edx            ; update pointer to next row
+       add edi, edx            ; ditto
+       add ebx, edx
+
+       sub  ecx,1
+       test ecx, ecx           ; check rowsleft
+       jnz near nextrowmm10
+               
+               ;; Sum the Accumulators
+       movq  mm4, mm0
+       psrlq mm4, 32
+       paddw mm0, mm4
+       movq  mm6, mm0
+       psrlq mm6, 16
+       paddw mm0, mm6
+       movd eax, mm0           ; store return value
+       and  eax, 0xffff
+
+               
+       pop edi
+       pop esi 
+       pop edx                 
+       pop ecx                 
+       pop ebx                 
+
+       pop ebp                 ; restore stack pointer
+
+       emms                    ; clear mmx registers
+       ret                     ; we now return you to your regular programming
+;
+;;;  dist1_01_mmx.s:  
+;;; 
+;  Copyright (C) 2000 Andrew Stevens <as@comlab.ox.ac.uk>
+
+;
+;  This program is free software; you can redistribute it and/or
+;  modify it under the terms of the GNU General Public License
+;  as published by the Free Software Foundation; either version 2
+;  of the License, or (at your option) any later version.
+;
+;  This program is distributed in the hope that it will be useful,
+;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;  GNU General Public License for more details.
+;
+;  You should have received a copy of the GNU General Public License
+;  along with this program; if not, write to the Free Software
+;  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+;
+;
+;
+
+
+global dist1_11_mmx
+
+; int dist1_11_mmx(unsigned char *p1,unsigned char *p2,int lx,int h);
+
+; esi = p1 (init:              blk1)
+; edi = p2 (init:              blk2)
+; ebx = p1+lx
+; ecx = rowsleft (init:         h)
+; edx = lx;
+
+; mm0 = distance accumulators (4 words)
+; mm1 = bytes p2
+; mm2 = bytes p1
+; mm3 = bytes p1+lx
+; I'd love to find someplace to stash p1+1 and p1+lx+1's bytes
+; but I don't think thats going to happen in iA32-land...
+; mm4 = temp 4 bytes in words interpolating p1, p1+1
+; mm5 = temp 4 bytes in words from p2
+; mm6 = temp comparison bit mask p1,p2
+; mm7 = temp comparison bit mask p2,p1
+
+
+align 32
+dist1_11_mmx:
+       push ebp                ; save stack pointer
+       mov ebp, esp    ; so that we can do this
+
+       push ebx                ; Saves registers (called saves convention in
+       push ecx                ; x86 GCC it seems)
+       push edx                ; 
+       push esi
+       push edi
+               
+       pxor mm0, mm0                           ; zero acculumators
+
+       mov esi, [ebp+8]                        ; get p1
+       mov edi, [ebp+12]                       ; get p2
+       mov edx, [ebp+16]                       ; get lx
+       mov ecx, [ebp+20]                       ; rowsleft := h
+       mov ebx, esi
+    add ebx, edx               
+       jmp nextrowmm11                                 ; snap to it
+align 32
+nextrowmm11:
+
+               ;; 
+               ;; First 8 bytes of row
+               ;; 
+               
+               ;; First 4 bytes of 8
+
+       movq mm4, [esi]             ; mm4 := first 4 bytes p1
+       pxor mm7, mm7
+       movq mm2, mm4                           ;  mm2 records all 8 bytes
+       punpcklbw mm4, mm7            ;  First 4 bytes p1 in Words...
+       
+       movq mm6, [ebx]                     ;  mm6 := first 4 bytes p1+lx
+       movq mm3, mm6               ;  mm3 records all 8 bytes
+       punpcklbw mm6, mm7
+       paddw mm4, mm6              
+
+
+       movq mm5, [esi+1]                       ; mm5 := first 4 bytes p1+1
+       punpcklbw mm5, mm7            ;  First 4 bytes p1 in Words...
+       paddw mm4, mm5          
+       movq mm6, [ebx+1]           ;  mm6 := first 4 bytes p1+lx+1
+       punpcklbw mm6, mm7
+       paddw mm4, mm6
+
+       psrlw mm4, 2                ; mm4 := First 4 bytes interpolated in words
+               
+       movq mm5, [edi]                         ; mm5:=first 4 bytes of p2 in words
+       movq mm1, mm5
+       punpcklbw mm5, mm7
+                       
+       movq  mm7,mm4
+       pcmpgtw mm7,mm5         ; mm7 := [i : W0..3,mm4>mm5]
+
+       movq  mm6,mm4           ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
+       psubw mm6,mm5
+       pand  mm6, mm7
+
+       paddw mm0, mm6                          ; Add to accumulator
+
+       movq  mm6,mm5       ; mm6 := [i : W0..3,mm5>mm4]
+       pcmpgtw mm6,mm4     
+       psubw mm5,mm4           ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
+       pand  mm5, mm6          
+
+       paddw mm0, mm5                          ; Add to accumulator
+
+               ;; Second 4 bytes of 8
+       
+       movq mm4, mm2               ; mm4 := Second 4 bytes p1 in words
+       pxor  mm7, mm7
+       punpckhbw mm4, mm7                      
+       movq mm6, mm3                   ; mm6 := Second 4 bytes p1+1 in words  
+       punpckhbw mm6, mm7
+       paddw mm4, mm6          
+
+       movq mm5, [esi+1]                       ; mm5 := first 4 bytes p1+1
+       punpckhbw mm5, mm7          ;  First 4 bytes p1 in Words...
+       paddw mm4, mm5
+       movq mm6, [ebx+1]           ;  mm6 := first 4 bytes p1+lx+1
+       punpckhbw mm6, mm7
+       paddw mm4, mm6
+
+       psrlw mm4, 2                ; mm4 := First 4 bytes interpolated in words
+               
+       movq mm5, mm1                   ; mm5:= second 4 bytes of p2 in words
+       punpckhbw mm5, mm7
+                       
+       movq  mm7,mm4
+       pcmpgtw mm7,mm5         ; mm7 := [i : W0..3,mm4>mm5]
+
+       movq  mm6,mm4           ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
+       psubw mm6,mm5
+       pand  mm6, mm7
+
+       paddw mm0, mm6                          ; Add to accumulator
+
+       movq  mm6,mm5       ; mm6 := [i : W0..3,mm5>mm4]
+       pcmpgtw mm6,mm4     
+       psubw mm5,mm4           ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
+       pand  mm5, mm6          
+
+       paddw mm0, mm5                          ; Add to accumulator
+
+
+               ;;
+               ;; Second 8 bytes of row
+               ;; 
+               ;; First 4 bytes of 8
+
+       movq mm4, [esi+8]             ; mm4 := first 4 bytes p1+8
+       pxor mm7, mm7
+       movq mm2, mm4                           ;  mm2 records all 8 bytes
+       punpcklbw mm4, mm7            ;  First 4 bytes p1 in Words...
+       
+       movq mm6, [ebx+8]                           ;  mm6 := first 4 bytes p1+lx+8
+       movq mm3, mm6               ;  mm3 records all 8 bytes
+       punpcklbw mm6, mm7
+       paddw mm4, mm6              
+
+
+       movq mm5, [esi+9]                       ; mm5 := first 4 bytes p1+9
+       punpcklbw mm5, mm7            ;  First 4 bytes p1 in Words...
+       paddw mm4, mm5
+       movq mm6, [ebx+9]           ;  mm6 := first 4 bytes p1+lx+9
+       punpcklbw mm6, mm7
+       paddw mm4, mm6
+
+       psrlw mm4, 2                ; mm4 := First 4 bytes interpolated in words
+               
+       movq mm5, [edi+8]                               ; mm5:=first 4 bytes of p2+8 in words
+       movq mm1, mm5
+       punpcklbw mm5, mm7
+                       
+       movq  mm7,mm4
+       pcmpgtw mm7,mm5         ; mm7 := [i : W0..3,mm4>mm5]
+
+       movq  mm6,mm4           ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
+       psubw mm6,mm5
+       pand  mm6, mm7
+
+       paddw mm0, mm6                          ; Add to accumulator
+
+       movq  mm6,mm5       ; mm6 := [i : W0..3,mm5>mm4]
+       pcmpgtw mm6,mm4     
+       psubw mm5,mm4           ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
+       pand  mm5, mm6          
+
+       paddw mm0, mm5                          ; Add to accumulator
+
+               ;; Second 4 bytes of 8
+       
+       movq mm4, mm2               ; mm4 := Second 4 bytes p1 in words
+       pxor  mm7, mm7
+       punpckhbw mm4, mm7                      
+       movq mm6, mm3                   ; mm6 := Second 4 bytes p1+1 in words  
+       punpckhbw mm6, mm7
+       paddw mm4, mm6          
+
+       movq mm5, [esi+9]                       ; mm5 := first 4 bytes p1+1
+       punpckhbw mm5, mm7          ;  First 4 bytes p1 in Words...
+       paddw mm4, mm5  
+       movq mm6, [ebx+9]           ;  mm6 := first 4 bytes p1+lx+1
+       punpckhbw mm6, mm7
+       paddw mm4, mm6
+               
+       psrlw mm4, 2                ; mm4 := First 4 bytes interpolated in words
+
+       movq mm5, mm1                   ; mm5:= second 4 bytes of p2 in words
+       punpckhbw mm5, mm7
+                       
+       movq  mm7,mm4
+       pcmpgtw mm7,mm5         ; mm7 := [i : W0..3,mm4>mm5]
+
+       movq  mm6,mm4           ; mm6 := [i : W0..3, (mm4-mm5)*(mm4-mm5 > 0)]
+       psubw mm6,mm5
+       pand  mm6, mm7
+
+       paddw mm0, mm6                          ; Add to accumulator
+
+       movq  mm6,mm5       ; mm6 := [i : W0..3,mm5>mm4]
+       pcmpgtw mm6,mm4     
+       psubw mm5,mm4           ; mm5 := [i : B0..7, (mm5-mm4)*(mm5-mm4 > 0)]
+       pand  mm5, mm6          
+
+       paddw mm0, mm5                          ; Add to accumulator
+
+
+               ;;
+               ;;      Loop termination condition... and stepping
+               ;;              
+
+       add esi, edx            ; update pointer to next row
+       add edi, edx            ; ditto
+       add ebx, edx
+
+       sub  ecx,1
+       test ecx, ecx           ; check rowsleft
+       jnz near nextrowmm11
+               
+               ;; Sum the Accumulators
+       movq  mm4, mm0
+       psrlq mm4, 32
+       paddw mm0, mm4
+       movq  mm6, mm0
+       psrlq mm6, 16
+       paddw mm0, mm6
+       movd eax, mm0           ; store return value
+       and  eax, 0xffff
+               
+       pop edi
+       pop esi 
+       pop edx                 
+       pop ecx                 
+       pop ebx                 
+
+       pop ebp                 ; restore stack pointer
+
+       emms                    ; clear mmx registers
+       ret                     ; we now return you to your regular programming
+
+
+global dist22_mmx
+
+; int dist22_mmx(unsigned char *blk1,unsigned char *blk2,int lx,int h);
+
+; eax = p1 (init:              blk1)
+; ebx = p2 (init:               blk2)
+; ecx = rowsleft (init:         h)
+; edx = lx;
+
+; mm0 = distance accumulators (4 words)
+; mm1 = temp 
+; mm2 = temp 
+; mm3 = temp
+; mm4 = temp
+; mm5 = temp 
+; mm6 = 0
+; mm7 = temp
+
+
+align 32
+dist22_mmx:
+       push ebp                ; save stack pointer
+       mov ebp, esp    ; so that we can do this
+
+       push ebx                ; Saves registers (called saves convention in
+       push ecx                ; x86 GCC it seems)
+       push edx                ; 
+
+       pxor mm0, mm0                           ; zero acculumators
+       pxor mm6, mm6
+       mov eax, [ebp+8]                        ; get p1
+       mov ebx, [ebp+12]                       ; get p2
+       mov edx, [ebp+16]                       ; get lx
+
+       mov  ecx, [ebp+20]                      ; get rowsleft
+
+       jmp nextrow                                     ; snap to it
+align 32
+nextrow:
+       movq mm4, [eax]         ; load 8 bytes of p1 
+       movq mm5, [ebx]         ; load 8 bytes of p2
+               
+       movq mm7, mm4       ; mm5 = abs(*p1-*p2)
+       psubusb mm7, mm5
+       psubusb mm5, mm4
+       add eax, edx            ; update pointer to next row
+       paddb   mm5,mm7 
+
+               ;;  Add the mm5 bytes to the accumulatores
+       movq  mm7,mm5                   
+       punpcklbw mm7,mm6
+       paddw mm0, mm7
+       punpckhbw mm5,mm6
+       add ebx, edx            ; update pointer to next row
+       paddw mm0, mm5
+       
+       movq mm4, [eax]         ; load 8 bytes of p1 (next row) 
+       movq mm5, [ebx]         ; load 8 bytes of p2 (next row)
+               
+       movq mm7, mm4       ; mm5 = abs(*p1-*p2)
+       psubusb mm7, mm5
+       psubusb mm5, mm4
+       add eax, edx            ; update pointer to next row
+       paddb   mm5,mm7 
+
+               ;;  Add the mm5 bytes to the accumulatores
+       movq  mm7,mm5                           
+       punpcklbw mm7,mm6
+       add ebx, edx            ; update pointer to next row
+       paddw mm0, mm7              
+       punpckhbw mm5,mm6
+       sub  ecx,2
+       paddw mm0, mm5
+
+
+       jnz nextrow
+
+               ;; Sum the Accumulators
+       movq  mm1, mm0
+       psrlq mm1, 16
+       movq  mm2, mm0
+       psrlq mm2, 32
+       movq  mm3, mm0
+       psrlq mm3, 48
+       paddw mm0, mm1
+       paddw mm2, mm3
+       paddw mm0, mm2
+               
+       movd eax, mm0           ; store return value
+       and  eax, 0xffff
+       
+       pop edx                 ; pop pop
+       pop ecx                 ; fizz fizz
+       pop ebx                 ; ia86 needs a fizz instruction
+
+       pop ebp                 ; restore stack pointer
+
+       emms                    ; clear mmx registers
+       ret                     ; we now return you to your regular programming
+
+
+
+
+global dist44_mmx
+
+; int dist44_mmx(unsigned char *blk1,unsigned char *blk2,int qlx,int qh);
+
+; eax = p1
+; ebx = p2
+; ecx = temp
+; edx = qlx;
+; esi = rowsleft
+
+; mm0 = distance accumulator left block p1
+; mm1 = distance accumulator right block p1
+; mm2 = 0
+; mm3 = right block of p1
+; mm4 = left block of p1
+; mm5 = p2
+; mm6 = temp
+; mm7 = temp
+
+align 32
+dist44_mmx:
+       push ebp                ; save stack pointer
+       mov ebp, esp            ; so that we can do this
+
+       push ebx
+       push ecx
+       push edx
+       push esi     
+
+       pxor mm0, mm0           ; zero acculumator
+       pxor mm1, mm1
+       pxor mm2, mm2
+       mov eax, [ebp+8]        ; get p1
+       mov ebx, [ebp+12]       ; get p2
+       mov edx, [ebp+16]       ; get qlx
+       mov esi, [ebp+20]       ; get rowsleft
+       jmp nextrowqd           ; snap to it
+align 32
+nextrowqd:
+
+               ;;
+               ;; Beware loop obfuscated by interleaving to try to
+               ;; hide latencies...
+               ;; 
+       movq mm4, [eax]                         ; mm4 =  first 4 bytes of p1 in words
+       movq mm5, [ebx]             ; mm5 = 4 bytes of p2 in words
+       movq mm3, mm4
+       punpcklbw mm4, mm2                      
+       punpcklbw mm5, mm2
+       
+       movq mm7, mm4
+       movq mm6, mm5
+       psubusw mm7, mm5
+       psubusw mm6, mm4
+       
+       add eax, edx                    ; update a pointer to next row
+;      punpckhbw mm3, mm2                      ; mm3 = 2nd 4 bytes of p1 in words
+
+       paddw   mm7, mm6
+       paddw mm0, mm7                          ; Add absolute differences to left block accumulators
+               
+;      movq mm7,mm3
+;      psubusw mm7, mm5
+;      psubusw mm5, mm3
+
+       add ebx, edx            ; update a pointer to next row
+       sub   esi, 1
+
+;      paddw   mm7, mm5
+;      paddw mm1, mm7                          ; Add absolute differences to right block accumulators
+       
+
+               
+       jnz nextrowqd           
+
+               ;;              Sum the accumulators
+
+       movq  mm4, mm0
+       psrlq mm4, 32
+       paddw mm0, mm4
+       movq  mm6, mm0
+       psrlq mm6, 16
+       paddw mm0, mm6
+       movd eax, mm0           ; store return value
+
+;      movq  mm4, mm1
+;      psrlq mm4, 32
+;      paddw mm1, mm4
+;      movq  mm6, mm1
+;      psrlq mm6, 16
+;      paddw mm1, mm6
+;      movd ebx, mm1
+
+       and  eax, 0xffff                
+;      sal  ebx, 16
+;      or   eax, ebx
+               
+       pop esi
+       pop edx
+       pop ecx
+       pop ebx
+
+       pop ebp                 ; restore stack pointer
+
+       emms                    ; clear mmx registers
+       ret                     ; we now return you to your regular programming
diff --git a/mpeg2enc/mblock_sad_mmxe.s b/mpeg2enc/mblock_sad_mmxe.s
new file mode 100644 (file)
index 0000000..0aec521
--- /dev/null
@@ -0,0 +1,607 @@
+;;; 
+;;;  mblock_sad_mmxe.s:  
+;;; 
+;;; Enhanced MMX optimized Sum Absolute Differences routines for macroblocks
+;;; (interpolated, 1-pel, 2*2 sub-sampled pel and 4*4 sub-sampled pel)
+;
+;  dist1_* Original Copyright (C) 2000 Chris Atenasio <chris@crud.net>
+;  Enhancements and rest Copyright (C) 2000 Andrew Stevens <as@comlab.ox.ac.uk>
+
+               ;; Yes, I tried prefetch-ing.  It makes no difference or makes
+               ;; stuff *slower*.
+
+;
+;  This program is free software; you can reaxstribute it and/or
+;  modify it under the terms of the GNU General Public License
+;  as published by the Free Software Foundation; either version 2
+;  of the License, or (at your option) any later version.
+;
+;  This program is distributed in the hope that it will be useful,
+;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;  GNU General Public License for more details.
+;
+;  You should have received a copy of the GNU General Public License
+;  along with this program; if not, write to the Free Software
+;  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+;
+;
+;
+
+
+global dist1_00_mmxe
+
+; int dist1_00(char *blk1,char *blk2,int lx,int h,int distlim);
+; distlim unused - costs more to check than the savings of
+; aborting the computation early from time to time...
+; eax = p1
+; ebx = p2
+; ecx = rowsleft
+; edx = lx;
+
+; mm0 = distance accumulator
+; mm1 = temp
+; mm2 = temp
+; mm3 = temp
+; mm4 = temp
+; mm5 = temp
+; mm6 = temp
+
+
+align 32
+dist1_00_mmxe:
+       push ebp                                        ; save frame pointer
+       mov ebp, esp                            ; link
+
+       push ebx
+       push ecx
+       push edx
+
+       pxor mm0, mm0           ; zero acculumator
+
+       mov eax, [ebp+8]        ; get p1
+dist1_00_0misalign:            
+       mov ebx, [ebp+12]       ; get p2
+       mov edx, [ebp+16]       ; get lx
+
+       mov ecx, [ebp+20]       ; get rowsleft
+       jmp nextrow00sse
+align 32
+nextrow00sse:
+       movq mm4, [eax]         ; load first 8 bytes of p1 (row 1)
+       psadbw mm4, [ebx]       ; compare to first 8 bytes of p2 (row 1)
+       movq mm5, [eax+8]       ; load next 8 bytes of p1 (row 1)
+       add eax, edx            ; update pointer to next row
+       paddd mm0, mm4          ; accumulate difference
+       
+       psadbw mm5, [ebx+8]     ; compare to next 8 bytes of p2 (row 1)
+       add ebx, edx            ; ditto
+       paddd mm0, mm5          ; accumulate difference
+
+
+       movq mm6, [eax]         ; load first 8 bytes of p1 (row 2)
+       psadbw mm6, [ebx]       ; compare to first 8 bytes of p2 (row 2)
+       movq mm4, [eax+8]       ; load next 8 bytes of p1 (row 2)
+       add eax, edx            ; update pointer to next row
+       paddd mm0, mm6          ; accumulate difference
+       
+       psadbw mm4, [ebx+8]     ; compare to next 8 bytes of p2 (row 2)
+       add ebx, edx            ; ditto
+       paddd mm0, mm4          ; accumulate difference
+
+       ;psubd mm2, mm3         ; decrease rowsleft
+       ;movq mm5, mm1          ; copy distlim
+       ;pcmpgtd mm5, mm0       ; distlim > dist?
+       ;pand mm2, mm5          ; mask rowsleft with answer
+       ;movd ecx, mm2          ; move rowsleft to ecx
+
+       ;add eax, edx           ; update pointer to next row
+       ;add ebx, edx           ; ditto
+       
+       ;test ecx, ecx          ; check rowsleft
+       sub  ecx, 2
+       jnz nextrow00sse
+
+       movd eax, mm0           ; store return value
+       
+       pop edx 
+       pop ecx 
+       pop ebx 
+
+       pop ebp 
+       emms
+       ret     
+
+
+                               
+
+global dist1_00_Ammxe
+               ;; This is a special version that only does aligned accesses...
+               ;; Wonder if it'll make it faster on a P-III
+               ;; ANSWER:               NO its slower hence no longer used.
+
+; int dist1_00(char *blk1,char *blk2,int lx,int h,int distlim);
+; distlim unused - costs more to check than the savings of
+; aborting the computation early from time to time...
+; eax = p1
+; ebx = p2
+; ecx = rowsleft
+; edx = lx;
+
+; mm0 = distance accumulator
+; mm1 = temp
+; mm2 = right shift to adjust for mis-align
+; mm3 = left shift to adjust for mis-align
+; mm4 = temp
+; mm5 = temp
+; mm6 = temp
+
+
+align 32
+dist1_00_Ammxe:
+       push ebp                                        ; save frame pointer
+       mov ebp, esp                            ; link
+
+       push ebx
+       push ecx
+       push edx
+               
+       pxor mm0, mm0           ; zero acculumator
+
+       mov eax, [ebp+8]        ; get p1
+       mov ebx, eax
+       and ebx, 7                                      ; Misalignment!
+       cmp ebx, 0
+       jz      near dist1_00_0misalign
+       sub eax, ebx                            ; Align eax
+       mov ecx, 8                                      ; ecx = 8-misalignment
+       sub ecx, ebx
+       shl ebx, 3                                      ; Convert into bit-shifts...
+       shl ecx, 3                                      
+       movd mm2, ebx                           ; mm2 = shift to start msb
+       movd mm3, ecx                           ; mm3 = shift to end lsb
+
+       mov ebx, [ebp+12]       ; get p2
+       mov edx, [ebp+16]       ; get lx
+       mov ecx, [ebp+20]       ; get rowsleft
+       jmp nextrow00ssea
+align 32
+nextrow00ssea:
+       movq mm4, [eax]                         ; load first 8 bytes of aligned p1 (row 1)
+       movq mm5, [eax+8]                       ; load next 8 bytes of aligned p1 (row 1)
+       movq mm6, mm5
+       psrlq mm4, mm2                          ; mm4 first 8 bytes of p1 proper
+       psllq mm5, mm3
+       por       mm4, mm5
+       psadbw mm4, [ebx]       ; compare to first 8 bytes of p2 
+
+       movq mm7, [eax+16]                      ; load last 8 bytes of aligned p1
+       add eax, edx            ; update pointer to next row
+       psrlq mm6, mm2                          ; mm6 2nd 8 bytes of p1 proper
+       psllq mm7, mm3
+       por   mm6, mm7
+
+
+       paddd mm0, mm4          ; accumulate difference
+       
+       psadbw mm6, [ebx+8]     ; compare to next 8 bytes of p2 (row 1)
+       add ebx, edx            ; ditto
+       paddd mm0, mm6          ; accumulate difference
+
+       sub  ecx, 1
+       jnz nextrow00ssea
+
+       movd eax, mm0           ; store return value
+
+       pop edx 
+       pop ecx 
+       pop ebx 
+
+       pop ebp 
+       emms
+       ret     
+
+
+global dist1_01_mmxe
+
+; int dist1_01(char *blk1,char *blk2,int lx,int h);
+
+; eax = p1
+; ebx = p2
+; ecx = counter temp
+; edx = lx;
+
+; mm0 = distance accumulator
+; mm1 = distlim
+; mm2 = rowsleft
+; mm3 = 2 (rows per loop)
+; mm4 = temp
+; mm5 = temp
+; mm6 = temp
+
+
+align 32
+dist1_01_mmxe:
+       push ebp        
+       mov ebp, esp
+
+       push ebx
+       push ecx
+       push edx
+
+       pxor mm0, mm0           ; zero acculumator
+
+       mov eax, [ebp+8]        ; get p1
+       mov ebx, [ebp+12]       ; get p2
+       mov edx, [ebp+16]       ; get lx
+
+       mov ecx, [ebp+20]       ; get rowsleft
+       jmp nextrow01           ; snap to it
+align 32
+nextrow01:
+       movq mm4, [eax]                         ; load first 8 bytes of p1 (row 1)
+       pavgb mm4, [eax+1]                      ; Interpolate...
+       psadbw mm4, [ebx]                       ; compare to first 8 bytes of p2 (row 1)
+       paddd mm0, mm4                          ; accumulate difference
+
+       movq mm5, [eax+8]                       ; load next 8 bytes of p1 (row 1)
+       pavgb mm5, [eax+9]                      ; Interpolate
+       psadbw mm5, [ebx+8]                     ; compare to next 8 bytes of p2 (row 1)
+       paddd mm0, mm5                          ; accumulate difference
+
+       add eax, edx                            ; update pointer to next row
+       add ebx, edx                            ; ditto
+
+       movq mm6, [eax]                         ; load first 8 bytes of p1 (row 2)
+       pavgb mm6, [eax+1]                      ; Interpolate
+       psadbw mm6, [ebx]       ; compare to first 8 bytes of p2 (row 2)
+       paddd mm0, mm6          ; accumulate difference
+       
+       movq mm7, [eax+8]       ; load next 8 bytes of p1 (row 2)
+       pavgb mm7, [eax+9]
+       psadbw mm7, [ebx+8]     ; compare to next 8 bytes of p2 (row 2)
+       paddd mm0, mm7          ; accumulate difference
+
+       add eax, edx            ; update pointer to next row
+       add ebx, edx            ; ditto
+       
+       sub ecx, 2                      ; check rowsleft
+       jnz nextrow01           ; rinse and repeat
+
+       movd eax, mm0           ; store return value
+       
+       pop edx 
+       pop ecx         
+       pop ebx 
+
+       pop ebp                 ; restore stack pointer
+
+       emms                    ; clear mmx registers
+       ret                     ; we now return you to your regular programming
+
+
+global dist1_10_mmxe
+
+; int dist1_10(char *blk1,char *blk2,int lx,int h);
+
+; eax = p1
+; ebx = p2
+; ecx = counter temp
+; edx = lx;
+; edi = p1+lx  
+
+; mm0 = distance accumulator
+; mm2 = rowsleft
+; mm3 = 2 (rows per loop)
+; mm4 = temp
+; mm5 = temp
+; mm6 = temp
+
+
+align 32
+dist1_10_mmxe:
+       push ebp                ; save stack pointer
+       mov ebp, esp
+
+       push ebx
+       push ecx
+       push edx
+       push edi
+
+       pxor mm0, mm0           ; zero acculumator
+
+       mov eax, [ebp+8]        ; get p1
+       mov ebx, [ebp+12]       ; get p2
+       mov edx, [ebp+16]       ; get lx
+       mov edi, eax
+       add edi, edx
+       mov ecx, [ebp+20]       ; get rowsleft
+       jmp nextrow10           ; snap to it
+align 32
+nextrow10:
+       movq mm4, [eax]                         ; load first 8 bytes of p1 (row 1)
+       pavgb mm4, [edi]                        ; Interpolate...
+       psadbw mm4, [ebx]                       ; compare to first 8 bytes of p2 (row 1)
+       paddd mm0, mm4                          ; accumulate difference
+
+       movq mm5, [eax+8]                       ; load next 8 bytes of p1 (row 1)
+       pavgb mm5, [edi+8]                      ; Interpolate
+       psadbw mm5, [ebx+8]                     ; compare to next 8 bytes of p2 (row 1)
+       paddd mm0, mm5                          ; accumulate difference
+
+       add eax, edx                            ; update pointer to next row
+       add ebx, edx                            ; ditto
+       add edi, edx
+
+       movq mm6, [eax]                         ; load first 8 bytes of p1 (row 2)
+       pavgb mm6, [edi]                        ; Interpolate
+       psadbw mm6, [ebx]       ; compare to first 8 bytes of p2 (row 2)
+       paddd mm0, mm6          ; accumulate difference
+       
+       movq mm7, [eax+8]       ; load next 8 bytes of p1 (row 2)
+       pavgb mm7, [edi+8]
+       psadbw mm7, [ebx+8]     ; compare to next 8 bytes of p2 (row 2)
+       paddd mm0, mm7          ; accumulate difference
+
+       psubd mm2, mm3          ; decrease rowsleft
+
+       add eax, edx            ; update pointer to next row
+       add ebx, edx            ; ditto
+       add edi, edx
+       
+       sub ecx, 2                      ; check rowsleft (we're doing 2 at a time)
+       jnz nextrow10           ; rinse and repeat
+
+       movd eax, mm0           ; store return value
+       
+       pop edi
+       pop edx 
+       pop ecx 
+       pop ebx 
+
+       pop ebp                 ; restore stack pointer
+
+       emms                    ; clear mmx registers
+       ret                     ; we now return you to your regular programming
+
+
+global dist1_11_mmxe
+
+; int dist1_11(char *blk1,char *blk2,int lx,int h);
+
+; eax = p1
+; ebx = p2
+; ecx = counter temp
+; edx = lx;
+; edi = p1+lx  
+
+                 
+; mm0 = distance accumulator
+; mm2 = rowsleft
+; mm3 = 2 (rows per loop)
+; mm4 = temp
+; mm5 = temp
+; mm6 = temp
+
+
+align 32
+dist1_11_mmxe:
+       push ebp                ; save stack pointer
+       mov ebp, esp            ; so that we can do this
+
+       push ebx                ; save the pigs
+       push ecx                ; make them squeal
+       push edx                ; lets have pigs for every meal
+       push edi
+
+       pxor mm0, mm0           ; zero acculumator
+
+       mov eax, [ebp+8]        ; get p1
+       mov ebx, [ebp+12]       ; get p2
+       mov edx, [ebp+16]       ; get lx
+       mov edi, eax
+       add edi, edx
+       mov ecx, [ebp+20]       ; get rowsleft
+       jmp nextrow11           ; snap to it
+align 32
+nextrow11:
+       movq mm4, [eax]                         ; load first 8 bytes of p1 (row 1)
+       pavgb mm4, [edi]                        ; Interpolate...
+       movq mm5, [eax+1]
+       pavgb mm5, [edi+1]
+       pavgb mm4, mm5
+       psadbw mm4, [ebx]                       ; compare to first 8 bytes of p2 (row 1)
+       paddd mm0, mm4                          ; accumulate difference
+
+       movq mm6, [eax+8]                       ; load next 8 bytes of p1 (row 1)
+       pavgb mm6, [edi+8]                      ; Interpolate
+       movq mm7, [eax+9]
+       pavgb mm7, [edi+9]
+       pavgb mm6, mm7
+       psadbw mm6, [ebx+8]                     ; compare to next 8 bytes of p2 (row 1)
+       paddd mm0, mm6                          ; accumulate difference
+
+       add eax, edx                            ; update pointer to next row
+       add ebx, edx                            ; ditto
+       add edi, edx
+
+       movq mm4, [eax]                         ; load first 8 bytes of p1 (row 1)
+       pavgb mm4, [edi]                        ; Interpolate...
+       movq mm5, [eax+1]
+       pavgb mm5, [edi+1]
+       pavgb mm4, mm5
+       psadbw mm4, [ebx]                       ; compare to first 8 bytes of p2 (row 1)
+       paddd mm0, mm4                          ; accumulate difference
+
+       movq mm6, [eax+8]                       ; load next 8 bytes of p1 (row 1)
+       pavgb mm6, [edi+8]                      ; Interpolate
+       movq mm7, [eax+9]
+       pavgb mm7, [edi+9]
+       pavgb mm6, mm7
+       psadbw mm6, [ebx+8]                     ; compare to next 8 bytes of p2 (row 1)
+       paddd mm0, mm6                          ; accumulate difference
+               
+       add eax, edx            ; update pointer to next row
+       add ebx, edx            ; ditto
+       add edi, edx
+
+                       
+       sub ecx, 2                              ; check rowsleft
+       jnz near nextrow11                      ; rinse and repeat
+
+       movd eax, mm0                           ; store return value
+       
+       pop edi
+       pop edx 
+       pop ecx         
+       pop ebx                 
+       
+       pop ebp                 ; restore stack pointer
+
+       emms                    ; clear mmx registers
+       ret                     ; we now return you to your regular programming
+
+global dist22_mmxe
+
+; int dist22_mmxe(unsigned char *blk1,unsigned char *blk2,int flx,int fh);
+
+; eax = p1
+; ebx = p2
+; ecx = counter temp
+; edx = flx;
+
+; mm0 = distance accumulator
+; mm2 = rowsleft
+; mm3 = 2 (rows per loop)
+; mm4 = temp
+; mm5 = temp
+; mm6 = temp
+
+
+align 32
+dist22_mmxe:
+       push ebp                ; save frame pointer
+       mov ebp, esp
+
+       push ebx        
+       push ecx
+       push edx        
+
+       pxor mm0, mm0           ; zero acculumator
+
+       mov eax, [ebp+8]        ; get p1
+       mov ebx, [ebp+12]       ; get p2
+       mov edx, [ebp+16]       ; get lx
+
+       mov ecx, [ebp+20]
+       jmp nextrowfd
+align 32
+nextrowfd:
+       movq   mm4, [eax]        ; load first 8 bytes of p1 (row 1) 
+       add eax, edx            ; update pointer to next row
+       psadbw mm4, [ebx]       ; compare to first 8 bytes of p2 (row 1)
+       add ebx, edx            ; ditto
+       paddd  mm0, mm4         ; accumulate difference
+       
+
+       movq mm6, [eax]         ; load first 8 bytes of p1 (row 2)
+       add eax, edx            ; update pointer to next row
+       psadbw mm6, [ebx]       ; compare to first 8 bytes of p2 (row 2)
+       add ebx, edx            ; ditto
+       paddd mm0, mm6          ; accumulate difference
+       
+
+       sub ecx, 2
+       jnz nextrowfd
+
+       movd eax, mm0
+       
+       pop edx 
+       pop ecx 
+       pop ebx 
+
+       pop ebp
+
+       emms
+       ret
+
+
+
+
+
+global dist44_mmxe
+
+; int dist44_mmxe(unsigned char *blk1,unsigned char *blk2,int qlx,int qh);
+
+; eax = p1
+; ebx = p2
+; ecx = temp
+; edx = qlx;
+; esi = rowsleft
+
+; mm0 = distance accumulator left block p1
+; mm1 = distance accumulator right block p1
+; mm2 = 0
+; mm3 = 0
+; mm4 = temp
+; mm5 = temp
+; mm6 = temp
+
+
+align 32
+dist44_mmxe:
+       push ebp
+       mov ebp, esp
+
+       push ebx
+       push ecx
+       push edx
+       push esi     
+
+       pxor mm0, mm0           ; zero acculumator
+       pxor mm1, mm1                           
+       pxor mm2, mm2
+       mov eax, [ebp+8]        ; get p1
+       mov ebx, [ebp+12]       ; get p2
+       mov edx, [ebp+16]       ; get qlx
+
+       mov esi, [ebp+20]       ; get rowsleft
+       jmp nextrowqd           ; snap to it
+align 32
+nextrowqd: 
+       movq mm4, [eax]                         ; load 8 bytes of p1 (two blocks!)
+       add eax, edx            ; update pointer to next row
+       movq mm6, mm4                             ;
+       mov  ecx, [ebx]       ; load 4 bytes of p2
+    punpcklbw mm4, mm2                 ; mm4 = bytes 0..3 p1 (spaced out)
+       movd mm5, ecx
+       punpcklbw mm5, mm2      ; mm5 = bytes 0..3 p2  (spaced out)
+       psadbw mm4, mm5                 ; compare to left block
+       add ebx, edx            ; ditto
+
+;      punpckhbw mm6, mm2          ; mm6 = bytes 4..7 p1 (spaced out)
+
+       paddd mm0, mm4                          ; accumulate difference left block
+
+;      psadbw mm6,mm5                          ; compare to right block
+       
+
+;      paddd mm1, mm6                          ; accumulate difference right block
+               
+       sub esi, 1
+       jnz nextrowqd
+
+       movd eax, mm0
+;      movd ebx, mm1                           
+;      sal  ebx, 16
+;      or   eax, ebx
+       
+       pop esi
+       pop edx
+       pop ecx
+       pop ebx
+
+       pop ebp                 ; restore stack pointer
+
+       emms                    ; clear mmx registers
+       ret                     ; we now return you to your regular programming
diff --git a/mpeg2enc/mblockq_sad_mmxe.s b/mpeg2enc/mblockq_sad_mmxe.s
new file mode 100644 (file)
index 0000000..0e57ea5
--- /dev/null
@@ -0,0 +1,411 @@
+;;; 
+;;;  mblockq_sad_mmxe.s:  
+;;; 
+;;; Enhanced MMX optimized Sum Absolute Differences routines for macroblock 
+;;; quads (2 by 2 squares of adjacent macroblocks)
+
+;;; Explanation: the motion compensation search at 1-pel and 2*2 sub-sampled
+;;; evaluates macroblock quads.  A lot of memory accesses can be saved
+;;; if each quad is done together rather than each macroblock in the
+;;; quad handled individually.
+
+;;; TODO:              Really there ought to be MMX versions and the function's
+;;; specification should be documented...
+;
+; Copyright (C) 2000 Andrew Stevens <as@comlab.ox.ac.uk>       
+
+
+;
+;  This program is free software; you can reaxstribute it and/or
+;  modify it under the terms of the GNU General Public License
+;  as published by the Free Software Foundation; either version 2
+;  of the License, or (at your option) any later version.
+;
+;  This program is distributed in the hope that it will be useful,
+;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;  GNU General Public License for more details.
+;
+;  You should have received a copy of the GNU General Public License
+;  along with this program; if not, write to the Free Software
+;  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+;
+;
+
+;;; CURRENTLY not used but used in testing as reference for tweaks...
+global mblockq_sad1_REF
+
+; void mblockq_dist1_REF(char *blk1,char *blk2,int lx,int h,int *weightvec);
+; eax = p1
+; ebx = p2
+; ecx = unused
+; edx = lx;
+; edi = rowsleft
+; esi = h
+               
+; mm0 = SAD (x+0,y+0)
+; mm1 = SAD (x+2,y+0)
+; mm2 = SAD (x+0,y+2)
+; mm3 = SAD (x+2,y+2)
+; mm4 = temp
+; mm5 = temp
+; mm6 = temp
+; mm7 = temp                                           
+
+align 32
+mblockq_dist1_REF:
+       push ebp                                        ; save frame pointer
+       mov ebp, esp                            ; link
+       push eax
+       push ebx
+       push ecx
+       push edx
+       push edi
+       push esi
+
+       pxor mm0, mm0           ; zero accumulators
+       pxor mm1, mm1
+       pxor mm2, mm2
+       pxor mm3, mm3
+       mov eax, [ebp+8]        ; get p1
+       mov ebx, [ebp+12]       ; get p2
+       mov edx, [ebp+16]       ; get lx
+       
+       mov edi, [ebp+20]       ; get rowsleft
+       mov esi, edi
+
+       jmp nextrow_block_d1
+align 32
+nextrow_block_d1:              
+
+               ;; Do the (+0,+0) SAD
+               
+       movq mm4, [eax]         ; load 1st 8 bytes of p1
+       movq mm6, mm4
+       movq mm5, [ebx]
+       psadbw mm4, mm5 ; compare to 1st 8 bytes of p2 
+       paddd mm0, mm4          ; accumulate difference
+       movq mm4, [eax+8]       ; load 2nd 8 bytes of p1
+       movq mm7, mm4           
+       psadbw mm4, [ebx+8]     ; compare to 2nd 8 bytes of p2 
+       paddd mm0, mm4          ; accumulate difference
+
+               
+    cmp edi, esi
+       jz  firstrow0
+
+               ;; Do the (0,+2) SAD
+       sub ebx, edx
+       psadbw mm6, [ebx]       ; compare to next 8 bytes of p2 (row 1)
+       paddd mm2, mm6          ; accumulate difference
+       psadbw mm7, [ebx+8]     ;  next 8 bytes of p1 (row 1)
+       add ebx, edx
+       paddd mm2, mm7  
+
+firstrow0:
+
+               ;; Do the (+2,0) SAD
+       
+       movq mm4, [eax+1]
+                               
+       movq mm6, mm4
+       psadbw mm4, mm5 ; compare to 1st 8 bytes of p2
+       paddd mm1, mm4          ; accumulate difference
+       movq mm4, [eax+9]
+       movq mm7, mm4
+       psadbw mm4, [ebx+8]     ; compare to 2nd 8 bytes of p2
+       paddd mm1, mm4          ; accumulate difference
+
+    cmp edi, esi
+       jz  firstrow1
+
+               ;; Do the (+2, +2 ) SAD
+       sub ebx, edx
+       psadbw mm6, [ebx]       ; compare to 1st 8 bytes of prev p2 
+       psadbw mm7, [ebx+8]     ;  2nd 8 bytes of prev p2
+       add ebx, edx
+       paddd mm3, mm6          ; accumulate difference
+       paddd mm3, mm7  
+firstrow1:             
+
+       add eax, edx                            ; update pointer to next row
+       add ebx, edx            ; ditto
+               
+       sub edi, 1
+       jnz near nextrow_block_d1
+
+               ;; Do the last row of the (0,+2) SAD
+
+       movq mm4, [eax]         ; load 1st 8 bytes of p1
+       movq mm5, [eax+8]       ; load 2nd 8 bytes of p1
+       sub  ebx, edx
+       psadbw mm4, [ebx]       ; compare to next 8 bytes of p2 (row 1)
+       psadbw mm5, [ebx+8]     ;  next 8 bytes of p1 (row 1)
+       paddd mm2, mm4          ; accumulate difference
+       paddd mm2, mm5
+               
+       movq mm4, [eax+1]
+       movq mm5, [eax+9]
+               
+               ;; Do the last row of rhw (+2, +2) SAD
+       psadbw mm4, [ebx]       ; compare to 1st 8 bytes of prev p2 
+       psadbw mm5, [ebx+8]     ;  2nd 8 bytes of prev p2
+       paddd mm3, mm4          ; accumulate difference
+       paddd mm3, mm5
+               
+
+       mov eax, [ebp+24]                       ; Weightvec
+       movd [eax+0], mm0
+       movd [eax+4], mm1
+       movd [eax+8], mm2
+       movd [eax+12], mm3
+               
+       pop esi
+       pop edi
+       pop edx 
+       pop ecx 
+       pop ebx 
+       pop eax
+               
+       pop ebp 
+       emms
+       ret     
+
+
+
+global mblockq_dist1_mmxe
+
+; void mblockq_dist1_mmxe(char *blk1,char *blk2,int lx,int h,int *weightvec);
+
+; eax = p1
+; ebx = p2
+; ecx = unused
+; edx = lx;
+; edi = rowsleft
+; esi = h
+               
+; mm0 = SAD (x+0,y+0),SAD (x+0,y+2)
+; mm1 = SAD (x+2,y+0),SAD (x+2,y+2)
+               
+; mm4 = temp
+; mm5 = temp
+; mm6 = temp
+; mm7 = temp                                           
+
+align 32
+mblockq_dist1_mmxe:
+       push ebp                                        ; save frame pointer
+       mov ebp, esp                            ; link
+       push eax
+       push ebx
+       push ecx
+       push edx
+       push edi
+       push esi
+
+       mov eax, [ebp+8]        ; get p1
+       prefetcht0 [eax]
+       pxor mm0, mm0           ; zero accumulators
+       pxor mm1, mm1
+       mov ebx, [ebp+12]       ; get p2
+       mov edx, [ebp+16]       ; get lx
+       
+       mov edi, [ebp+20]       ; get rowsleft
+       mov esi, edi
+
+       jmp nextrow_block_e1
+align 32
+nextrow_block_e1:              
+
+               ;; Do the (+0,+0) SAD
+       prefetcht0 [eax+edx]            
+       movq mm4, [eax]         ; load 1st 8 bytes of p1
+       movq mm6, mm4
+       movq mm5, [ebx]
+       psadbw mm4, mm5 ; compare to 1st 8 bytes of p2 
+       paddd mm0, mm4          ; accumulate difference
+       movq mm4, [eax+8]       ; load 2nd 8 bytes of p1
+       movq mm7, mm4           
+       psadbw mm4, [ebx+8]     ; compare to 2nd 8 bytes of p2 
+       paddd mm0, mm4          ; accumulate difference
+
+               
+    cmp edi, esi
+       jz  firstrowe0
+
+               ;; Do the (0,+2) SAD
+       sub ebx, edx
+       pshufw  mm0, mm0, 2*1 + 3 * 4 + 0 * 16 + 1 * 64
+       movq   mm2, [ebx]
+       psadbw mm6, mm2     ; compare to next 8 bytes of p2 (row 1)
+       paddd mm0, mm6          ; accumulate difference
+       movq  mm3, [ebx+8]
+       psadbw mm7, mm3 ;  next 8 bytes of p1 (row 1)
+       add ebx, edx
+       paddd mm0, mm7  
+       pshufw  mm0, mm0, 2*1 + 3 * 4 + 0 * 16 + 1 * 64 
+firstrowe0:
+
+               ;; Do the (+2,0) SAD
+       
+       movq mm4, [eax+1]
+       movq mm6, mm4
+
+       psadbw mm4, mm5 ; compare to 1st 8 bytes of p2
+       paddd mm1, mm4          ; accumulate difference
+
+       movq mm4, [eax+9]
+       movq mm7, mm4
+
+       psadbw mm4, [ebx+8]     ; compare to 2nd 8 bytes of p2
+       paddd mm1, mm4          ; accumulate difference
+
+    cmp edi, esi
+       jz  firstrowe1
+
+               ;; Do the (+2, +2 ) SAD
+       sub ebx, edx
+       pshufw  mm1, mm1, 2*1 + 3 * 4 + 0 * 16 + 1 * 64 
+       psadbw mm6, mm2 ; compare to 1st 8 bytes of prev p2 
+       psadbw mm7, mm3 ;  2nd 8 bytes of prev p2
+       add ebx, edx
+       paddd mm1, mm6          ; accumulate difference
+       paddd mm1, mm7
+       pshufw  mm1, mm1, 2*1 + 3 * 4 + 0 * 16 + 1 * 64 
+firstrowe1:            
+
+       add eax, edx                            ; update pointer to next row
+       add ebx, edx            ; ditto
+               
+       sub edi, 1
+       jnz near nextrow_block_e1
+
+               ;; Do the last row of the (0,+2) SAD
+       pshufw  mm0, mm0, 2*1 + 3 * 4 + 0 * 16 + 1 * 64
+       movq mm4, [eax]         ; load 1st 8 bytes of p1
+       movq mm5, [eax+8]       ; load 2nd 8 bytes of p1
+       sub  ebx, edx
+       psadbw mm4, [ebx]       ; compare to next 8 bytes of p2 (row 1)
+       psadbw mm5, [ebx+8]     ;  next 8 bytes of p1 (row 1)
+       paddd mm0, mm4          ; accumulate difference
+       paddd mm0, mm5
+
+               
+               ;; Do the last row of rhw (+2, +2) SAD
+       pshufw  mm1, mm1, 2*1 + 3 * 4 + 0 * 16 + 1 * 64                         
+       movq mm4, [eax+1]
+       movq mm5, [eax+9]
+
+       psadbw mm4, [ebx]       ; compare to 1st 8 bytes of prev p2 
+       psadbw mm5, [ebx+8]     ;  2nd 8 bytes of prev p2
+       paddd mm1, mm4          ; accumulate difference
+       paddd mm1, mm5
+               
+
+       mov eax, [ebp+24]                       ; Weightvec
+       movd [eax+8], mm0
+       pshufw  mm0, mm0, 2*1 + 3 * 4 + 0 * 16 + 1 * 64
+       movd [eax+12], mm1
+       pshufw  mm1, mm1, 2*1 + 3 * 4 + 0 * 16 + 1 * 64
+       movd [eax+0], mm0
+       movd [eax+4], mm1
+               
+       pop esi
+       pop edi
+       pop edx 
+       pop ecx 
+       pop ebx 
+       pop eax
+               
+       pop ebp 
+       emms
+       ret
+
+global mblockq_dist22_mmxe
+
+; void mblockq_dist22_mmxe(unsigned char *blk1,unsigned char *blk2,int flx,int fh, int* resvec);
+
+; eax = p1
+; ebx = p2
+; ecx = counter temp
+; edx = flx;
+
+; mm0 = distance accumulator
+; mm1 = distance accumulator
+; mm2 = previous p1 row
+; mm3 = previous p1 displaced by 1 byte...
+; mm4 = temp
+; mm5 = temp
+; mm6 = temp
+; mm7 = temp / 0 if first row 0xff otherwise
+
+
+align 32
+mblockq_dist22_mmxe:
+       push ebp                ; save frame pointer
+       mov ebp, esp
+       push eax
+       push ebx        
+       push ecx
+       push edx        
+
+       pxor mm0, mm0           ; zero acculumator
+       pxor mm1, mm1           ; zero acculumator
+       pxor mm2, mm2           ; zero acculumator
+       pxor mm3, mm3           ; zero acculumator                                              
+
+       mov eax, [ebp+8]        ; get p1
+       mov ebx, [ebp+12]       ; get p2
+       mov edx, [ebp+16]       ; get lx
+       mov ecx, [ebp+20]
+       movq mm2, [eax+edx]
+       movq mm3, [eax+edx+1]
+       jmp nextrowbd22
+align 32
+nextrowbd22:
+       movq   mm5, [ebx]                       ; load previous row reference block
+                                                               ; mm2 /mm3 containts current row target block
+               
+       psadbw mm2, mm5                         ; Comparse (x+0,y+2)
+       paddd  mm1, mm2
+               
+       psadbw mm3, mm5                         ; Compare (x+2,y+2)
+       pshufw  mm1, mm1, 2*1 + 3 * 4 + 0 * 16 + 1 * 64
+       paddd  mm1, mm3
+
+       pshufw  mm1, mm1, 2*1 + 3 * 4 + 0 * 16 + 1 * 64                                         
+
+       movq mm2, [eax]                         ; Load current row traget block into mm2 / mm3
+       movq mm6, mm2
+       movq mm3, [eax+1]
+       sub        eax, edx
+       sub        ebx, edx
+       prefetcht0 [eax]
+       movq mm7, mm3           
+
+       psadbw  mm6, mm5                        ; Compare (x+0,y+0)
+       paddd   mm0, mm6
+       pshufw  mm0, mm0, 2*1 + 3 * 4 + 0 * 16 + 1 * 64
+       psadbw  mm7, mm5                        ; Compare (x+2,y+0)
+       paddd   mm0, mm7
+       pshufw  mm0, mm0, 2*1 + 3 * 4 + 0 * 16 + 1 * 64
+
+       sub ecx, 1
+       jnz nextrowbd22
+
+       mov  eax, [ebp+24]
+       movq [eax+0], mm0
+       movq [eax+8], mm1
+       pop edx 
+       pop ecx 
+       pop ebx 
+       pop eax
+       pop ebp
+
+       emms
+       ret
+               
+
+
+
+
diff --git a/mpeg2enc/mmx.h b/mpeg2enc/mmx.h
new file mode 100644 (file)
index 0000000..e7f5b7e
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * mmx.h
+ * Copyright (C) 1997-1999 H. Dietz and R. Fisher
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ *
+ * mpeg2dec is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mpeg2dec is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * The type of an value that fits in an MMX register (note that long
+ * long constant values MUST be suffixed by LL and unsigned long long
+ * values by ULL, lest they be truncated by the compiler)
+ */
+
+typedef        union {
+       long long               q;      /* Quadword (64-bit) value */
+       unsigned long long      uq;     /* Unsigned Quadword */
+       int                     d[2];   /* 2 Doubleword (32-bit) values */
+       unsigned int            ud[2];  /* 2 Unsigned Doubleword */
+       short                   w[4];   /* 4 Word (16-bit) values */
+       unsigned short          uw[4];  /* 4 Unsigned Word */
+       char                    b[8];   /* 8 Byte (8-bit) values */
+       unsigned char           ub[8];  /* 8 Unsigned Byte */
+       float                   s[2];   /* Single-precision (32-bit) value */
+} ATTR_ALIGN(8) mmx_t; /* On an 8-byte (64-bit) boundary */
+
+
+#define        mmx_i2r(op,imm,reg) \
+       __asm__ __volatile__ (#op " %0, %%" #reg \
+                             : /* nothing */ \
+                             : "X" (imm) )
+
+#define        mmx_m2r(op,mem,reg) \
+       __asm__ __volatile__ (#op " %0, %%" #reg \
+                             : /* nothing */ \
+                             : "X" (mem))
+
+#define        mmx_r2m(op,reg,mem) \
+       __asm__ __volatile__ (#op " %%" #reg ", %0" \
+                             : "=X" (mem) \
+                             : /* nothing */ )
+
+#define        mmx_r2r(op,regs,regd) \
+       __asm__ __volatile__ (#op " %" #regs ", %" #regd)
+
+
+#define        emms() __asm__ __volatile__ ("emms")
+#define        femms() __asm__ __volatile__ ("femms")
+
+#define        movd_m2r(var,reg)       mmx_m2r (movd, var, reg)
+#define        movd_r2m(reg,var)       mmx_r2m (movd, reg, var)
+#define        movd_r2r(regs,regd)     mmx_r2r (movd, regs, regd)
+
+#define        movq_m2r(var,reg)       mmx_m2r (movq, var, reg)
+#define        movq_r2m(reg,var)       mmx_r2m (movq, reg, var)
+#define        movq_r2r(regs,regd)     mmx_r2r (movq, regs, regd)
+
+#define        packssdw_m2r(var,reg)   mmx_m2r (packssdw, var, reg)
+#define        packssdw_r2r(regs,regd) mmx_r2r (packssdw, regs, regd)
+#define        packsswb_m2r(var,reg)   mmx_m2r (packsswb, var, reg)
+#define        packsswb_r2r(regs,regd) mmx_r2r (packsswb, regs, regd)
+
+#define        packuswb_m2r(var,reg)   mmx_m2r (packuswb, var, reg)
+#define        packuswb_r2r(regs,regd) mmx_r2r (packuswb, regs, regd)
+
+#define        paddb_m2r(var,reg)      mmx_m2r (paddb, var, reg)
+#define        paddb_r2r(regs,regd)    mmx_r2r (paddb, regs, regd)
+#define        paddd_m2r(var,reg)      mmx_m2r (paddd, var, reg)
+#define        paddd_r2r(regs,regd)    mmx_r2r (paddd, regs, regd)
+#define        paddw_m2r(var,reg)      mmx_m2r (paddw, var, reg)
+#define        paddw_r2r(regs,regd)    mmx_r2r (paddw, regs, regd)
+
+#define        paddsb_m2r(var,reg)     mmx_m2r (paddsb, var, reg)
+#define        paddsb_r2r(regs,regd)   mmx_r2r (paddsb, regs, regd)
+#define        paddsw_m2r(var,reg)     mmx_m2r (paddsw, var, reg)
+#define        paddsw_r2r(regs,regd)   mmx_r2r (paddsw, regs, regd)
+
+#define        paddusb_m2r(var,reg)    mmx_m2r (paddusb, var, reg)
+#define        paddusb_r2r(regs,regd)  mmx_r2r (paddusb, regs, regd)
+#define        paddusw_m2r(var,reg)    mmx_m2r (paddusw, var, reg)
+#define        paddusw_r2r(regs,regd)  mmx_r2r (paddusw, regs, regd)
+
+#define        pand_m2r(var,reg)       mmx_m2r (pand, var, reg)
+#define        pand_r2r(regs,regd)     mmx_r2r (pand, regs, regd)
+
+#define        pandn_m2r(var,reg)      mmx_m2r (pandn, var, reg)
+#define        pandn_r2r(regs,regd)    mmx_r2r (pandn, regs, regd)
+
+#define        pcmpeqb_m2r(var,reg)    mmx_m2r (pcmpeqb, var, reg)
+#define        pcmpeqb_r2r(regs,regd)  mmx_r2r (pcmpeqb, regs, regd)
+#define        pcmpeqd_m2r(var,reg)    mmx_m2r (pcmpeqd, var, reg)
+#define        pcmpeqd_r2r(regs,regd)  mmx_r2r (pcmpeqd, regs, regd)
+#define        pcmpeqw_m2r(var,reg)    mmx_m2r (pcmpeqw, var, reg)
+#define        pcmpeqw_r2r(regs,regd)  mmx_r2r (pcmpeqw, regs, regd)
+
+#define        pcmpgtb_m2r(var,reg)    mmx_m2r (pcmpgtb, var, reg)
+#define        pcmpgtb_r2r(regs,regd)  mmx_r2r (pcmpgtb, regs, regd)
+#define        pcmpgtd_m2r(var,reg)    mmx_m2r (pcmpgtd, var, reg)
+#define        pcmpgtd_r2r(regs,regd)  mmx_r2r (pcmpgtd, regs, regd)
+#define        pcmpgtw_m2r(var,reg)    mmx_m2r (pcmpgtw, var, reg)
+#define        pcmpgtw_r2r(regs,regd)  mmx_r2r (pcmpgtw, regs, regd)
+
+#define        pmaddwd_m2r(var,reg)    mmx_m2r (pmaddwd, var, reg)
+#define        pmaddwd_r2r(regs,regd)  mmx_r2r (pmaddwd, regs, regd)
+
+#define        pmulhw_m2r(var,reg)     mmx_m2r (pmulhw, var, reg)
+#define        pmulhw_r2r(regs,regd)   mmx_r2r (pmulhw, regs, regd)
+
+#define        pmullw_m2r(var,reg)     mmx_m2r (pmullw, var, reg)
+#define        pmullw_r2r(regs,regd)   mmx_r2r (pmullw, regs, regd)
+
+#define        por_m2r(var,reg)        mmx_m2r (por, var, reg)
+#define        por_r2r(regs,regd)      mmx_r2r (por, regs, regd)
+
+#define        pslld_i2r(imm,reg)      mmx_i2r (pslld, imm, reg)
+#define        pslld_m2r(var,reg)      mmx_m2r (pslld, var, reg)
+#define        pslld_r2r(regs,regd)    mmx_r2r (pslld, regs, regd)
+#define        psllq_i2r(imm,reg)      mmx_i2r (psllq, imm, reg)
+#define        psllq_m2r(var,reg)      mmx_m2r (psllq, var, reg)
+#define        psllq_r2r(regs,regd)    mmx_r2r (psllq, regs, regd)
+#define        psllw_i2r(imm,reg)      mmx_i2r (psllw, imm, reg)
+#define        psllw_m2r(var,reg)      mmx_m2r (psllw, var, reg)
+#define        psllw_r2r(regs,regd)    mmx_r2r (psllw, regs, regd)
+
+#define        psrad_i2r(imm,reg)      mmx_i2r (psrad, imm, reg)
+#define        psrad_m2r(var,reg)      mmx_m2r (psrad, var, reg)
+#define        psrad_r2r(regs,regd)    mmx_r2r (psrad, regs, regd)
+#define        psraw_i2r(imm,reg)      mmx_i2r (psraw, imm, reg)
+#define        psraw_m2r(var,reg)      mmx_m2r (psraw, var, reg)
+#define        psraw_r2r(regs,regd)    mmx_r2r (psraw, regs, regd)
+
+#define        psrld_i2r(imm,reg)      mmx_i2r (psrld, imm, reg)
+#define        psrld_m2r(var,reg)      mmx_m2r (psrld, var, reg)
+#define        psrld_r2r(regs,regd)    mmx_r2r (psrld, regs, regd)
+#define        psrlq_i2r(imm,reg)      mmx_i2r (psrlq, imm, reg)
+#define        psrlq_m2r(var,reg)      mmx_m2r (psrlq, var, reg)
+#define        psrlq_r2r(regs,regd)    mmx_r2r (psrlq, regs, regd)
+#define        psrlw_i2r(imm,reg)      mmx_i2r (psrlw, imm, reg)
+#define        psrlw_m2r(var,reg)      mmx_m2r (psrlw, var, reg)
+#define        psrlw_r2r(regs,regd)    mmx_r2r (psrlw, regs, regd)
+
+#define        psubb_m2r(var,reg)      mmx_m2r (psubb, var, reg)
+#define        psubb_r2r(regs,regd)    mmx_r2r (psubb, regs, regd)
+#define        psubd_m2r(var,reg)      mmx_m2r (psubd, var, reg)
+#define        psubd_r2r(regs,regd)    mmx_r2r (psubd, regs, regd)
+#define        psubw_m2r(var,reg)      mmx_m2r (psubw, var, reg)
+#define        psubw_r2r(regs,regd)    mmx_r2r (psubw, regs, regd)
+
+#define        psubsb_m2r(var,reg)     mmx_m2r (psubsb, var, reg)
+#define        psubsb_r2r(regs,regd)   mmx_r2r (psubsb, regs, regd)
+#define        psubsw_m2r(var,reg)     mmx_m2r (psubsw, var, reg)
+#define        psubsw_r2r(regs,regd)   mmx_r2r (psubsw, regs, regd)
+
+#define        psubusb_m2r(var,reg)    mmx_m2r (psubusb, var, reg)
+#define        psubusb_r2r(regs,regd)  mmx_r2r (psubusb, regs, regd)
+#define        psubusw_m2r(var,reg)    mmx_m2r (psubusw, var, reg)
+#define        psubusw_r2r(regs,regd)  mmx_r2r (psubusw, regs, regd)
+
+#define        punpckhbw_m2r(var,reg)          mmx_m2r (punpckhbw, var, reg)
+#define        punpckhbw_r2r(regs,regd)        mmx_r2r (punpckhbw, regs, regd)
+#define        punpckhdq_m2r(var,reg)          mmx_m2r (punpckhdq, var, reg)
+#define        punpckhdq_r2r(regs,regd)        mmx_r2r (punpckhdq, regs, regd)
+#define        punpckhwd_m2r(var,reg)          mmx_m2r (punpckhwd, var, reg)
+#define        punpckhwd_r2r(regs,regd)        mmx_r2r (punpckhwd, regs, regd)
+
+#define        punpcklbw_m2r(var,reg)          mmx_m2r (punpcklbw, var, reg)
+#define        punpcklbw_r2r(regs,regd)        mmx_r2r (punpcklbw, regs, regd)
+#define        punpckldq_m2r(var,reg)          mmx_m2r (punpckldq, var, reg)
+#define        punpckldq_r2r(regs,regd)        mmx_r2r (punpckldq, regs, regd)
+#define        punpcklwd_m2r(var,reg)          mmx_m2r (punpcklwd, var, reg)
+#define        punpcklwd_r2r(regs,regd)        mmx_r2r (punpcklwd, regs, regd)
+
+#define        pxor_m2r(var, reg)      mmx_m2r (pxor, var, reg)
+#define        pxor_r2r(regs, regd)    mmx_r2r (pxor, regs, regd)
+
+/* AMD MMX extensions - also available in intel SSE */
+
+
+#define mmx_m2ri(op,mem,reg,imm) \
+        __asm__ __volatile__ (#op " %1, %0, %%" #reg \
+                              : /* nothing */ \
+                              : "X" (mem), "X" (imm))
+#define mmx_r2ri(op,regs,regd,imm) \
+        __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \
+                              : /* nothing */ \
+                              : "X" (imm) )
+
+#define        mmx_fetch(mem,hint) \
+       __asm__ __volatile__ ("prefetch" #hint " %0" \
+                             : /* nothing */ \
+                             : "X" (mem))
+
+/* 3DNow goodies */
+#define pfmul_m2r(var,reg) mmx_m2r( pfmul, var, reg )
+#define pfmul_r2r(regs,regd) mmx_r2r( pfmul, regs, regd )
+#define pfadd_m2r(var,reg) mmx_m2r( pfadd, var, reg )
+#define pfadd_r2r(regs,regd) mmx_r2r( pfadd, regs, regd )
+#define pf2id_r2r(regs,regd) mmx_r2r( pf2id, regs, regd )
+#define pi2fd_r2r(regs,regd) mmx_r2r( pi2fd, regs, regd )
+
+/* SSE goodies */
+#define mulps_r2r( regs, regd) mmx_r2r( mulps, regs, regd )
+#define mulps_m2r( var, regd) mmx_m2r( mulps, var, regd )
+#define movups_m2r(var, reg) mmx_m2r( movups, var, reg )
+#define movaps_m2r(var, reg) mmx_m2r( movaps, var, reg )
+#define movups_r2m(reg, var) mmx_r2m( movups, reg, var )
+#define movaps_r2m(reg, var) mmx_r2m( movaps, reg, var )
+#define cvtps2pi_r2r(regs,regd) mmx_r2r( cvtps2pi, regs, regd )
+#define cvtpi2ps_r2r(regs,regd) mmx_r2r( cvtpi2ps, regs, regd )
+#define shufps_r2ri(regs, regd, imm) mmx_r2ri( shufps, regs, regd, imm )
+
+
+#define        maskmovq(regs,maskreg)          mmx_r2ri (maskmovq, regs, maskreg)
+
+#define        movntq_r2m(mmreg,var)           mmx_r2m (movntq, mmreg, var)
+
+#define        pavgb_m2r(var,reg)              mmx_m2r (pavgb, var, reg)
+#define        pavgb_r2r(regs,regd)            mmx_r2r (pavgb, regs, regd)
+#define        pavgw_m2r(var,reg)              mmx_m2r (pavgw, var, reg)
+#define        pavgw_r2r(regs,regd)            mmx_r2r (pavgw, regs, regd)
+
+#define        pextrw_r2r(mmreg,reg,imm)       mmx_r2ri (pextrw, mmreg, reg, imm)
+
+#define        pinsrw_r2r(reg,mmreg,imm)       mmx_r2ri (pinsrw, reg, mmreg, imm)
+
+#define        pmaxsw_m2r(var,reg)             mmx_m2r (pmaxsw, var, reg)
+#define        pmaxsw_r2r(regs,regd)           mmx_r2r (pmaxsw, regs, regd)
+
+#define        pmaxub_m2r(var,reg)             mmx_m2r (pmaxub, var, reg)
+#define        pmaxub_r2r(regs,regd)           mmx_r2r (pmaxub, regs, regd)
+
+#define        pminsw_m2r(var,reg)             mmx_m2r (pminsw, var, reg)
+#define        pminsw_r2r(regs,regd)           mmx_r2r (pminsw, regs, regd)
+
+#define        pminub_m2r(var,reg)             mmx_m2r (pminub, var, reg)
+#define        pminub_r2r(regs,regd)           mmx_r2r (pminub, regs, regd)
+
+#define        pmovmskb(mmreg,reg) \
+       __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg)
+
+#define        pmulhuw_m2r(var,reg)            mmx_m2r (pmulhuw, var, reg)
+#define        pmulhuw_r2r(regs,regd)          mmx_r2r (pmulhuw, regs, regd)
+
+#define        prefetcht0(mem)                 mmx_fetch (mem, t0)
+#define        prefetcht1(mem)                 mmx_fetch (mem, t1)
+#define        prefetcht2(mem)                 mmx_fetch (mem, t2)
+#define        prefetchnta(mem)                mmx_fetch (mem, nta)
+
+#define        psadbw_m2r(var,reg)             mmx_m2r (psadbw, var, reg)
+#define        psadbw_r2r(regs,regd)           mmx_r2r (psadbw, regs, regd)
+
+#define        pshufw_m2ri(var,reg,imm)        mmx_m2ri( pshufw, var, reg, imm)
+#define        pshufw_r2ri(regs,regd,imm)      mmx_r2ri( pshufw, regs, regd, imm)
+
+#define        sfence() __asm__ __volatile__ ("sfence\n\t")
diff --git a/mpeg2enc/mpeg2enc.h b/mpeg2enc/mpeg2enc.h
new file mode 100644 (file)
index 0000000..fb6624e
--- /dev/null
@@ -0,0 +1,130 @@
+/* mpg2enc.h, defines and types                                             */
+
+/* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. */
+
+/*
+ * Disclaimer of Warranty
+ *
+ * These software programs are available to the user without any license fee or
+ * royalty on an "as is" basis.  The MPEG Software Simulation Group disclaims
+ * any and all warranties, whether express, implied, or statuary, including any
+ * implied warranties or merchantability or of fitness for a particular
+ * purpose.  In no event shall the copyright-holder be liable for any
+ * incidental, punitive, or consequential damages of any kind whatsoever
+ * arising from the use of these programs.
+ *
+ * This disclaimer of warranty extends to the user of these programs and user's
+ * customers, employees, agents, transferees, successors, and assigns.
+ *
+ * The MPEG Software Simulation Group does not represent or warrant that the
+ * programs furnished hereunder are free of infringement of any third-party
+ * patents.
+ *
+ * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware,
+ * are subject to royalty fees to patent holders.  Many of these patents are
+ * general enough such that they are unavoidable regardless of implementation
+ * design.
+ *
+ */
+
+#ifndef MPEG2ENC_H
+#define MPEG2ENC_H
+
+#define PICTURE_START_CODE 0x100L
+#define SLICE_MIN_START    0x101L
+#define SLICE_MAX_START    0x1AFL
+#define USER_START_CODE    0x1B2L
+#define SEQ_START_CODE     0x1B3L
+#define EXT_START_CODE     0x1B5L
+#define SEQ_END_CODE       0x1B7L
+#define GOP_START_CODE     0x1B8L
+#define ISO_END_CODE       0x1B9L
+#define PACK_START_CODE    0x1BAL
+#define SYSTEM_START_CODE  0x1BBL
+
+/* picture coding type */
+#define I_TYPE 1
+#define P_TYPE 2
+#define B_TYPE 3
+#define D_TYPE 4
+
+/* picture structure */
+#define TOP_FIELD     1
+#define BOTTOM_FIELD  2
+#define FRAME_PICTURE 3
+
+/* macroblock type */
+#define MB_INTRA    1
+#define MB_PATTERN  2
+#define MB_BACKWARD 4
+#define MB_FORWARD  8
+#define MB_QUANT    16
+
+/* motion_type */
+#define MC_FIELD 1
+#define MC_FRAME 2
+#define MC_16X8  2
+#define MC_DMV   3
+
+/* mv_format */
+#define MV_FIELD 0
+#define MV_FRAME 1
+
+/* chroma_format */
+#define CHROMA420 1
+#define CHROMA422 2
+#define CHROMA444 3
+
+/* extension start code IDs */
+
+#define SEQ_ID       1
+#define DISP_ID      2
+#define QUANT_ID     3
+#define SEQSCAL_ID   5
+#define PANSCAN_ID   7
+#define CODING_ID    8
+#define SPATSCAL_ID  9
+#define TEMPSCAL_ID 10
+
+/* inputtype */
+#define T_Y_U_V 0
+#define T_YUV   1
+#define T_PPM   2
+#define T_QUICKTIME 3
+#define T_MPEG 4
+#define T_STDIN 5
+#define T_BUFFERS 6
+
+#define BUFFER_ALIGN 16
+
+/* macroblock information */
+struct mbinfo {
+       int mb_type; /* intra/forward/backward/interpolated */
+       int motion_type; /* frame/field/16x8/dual_prime */
+       int dct_type; /* field/frame DCT */
+       int mquant; /* quantization parameter */
+       int cbp; /* coded block pattern */
+       int skipped; /* skipped macroblock */
+       int MV[2][2][2]; /* motion vectors */
+       int mv_field_sel[2][2]; /* motion vertical field select */
+       int dmvector[2]; /* dual prime vectors */
+       double act; /* activity measure */
+       int i_act;  /* Activity measure if intra coded (I/P-frame) */
+       int p_act;  /* Activity measure for *forward* prediction (P-frame) */
+       int b_act;      /* Activity measure if bi-directionally coded (B-frame) */
+       int var;        /* Macroblock luminance variance (measure of activity) */
+       short (*dctblocks)[64];
+};
+
+/* motion data */
+struct motion_data {
+  int forw_hor_f_code,forw_vert_f_code; /* vector range */
+  int sxf,syf; /* search range */
+  int back_hor_f_code,back_vert_f_code;
+  int sxb,syb;
+};
+
+
+
+
+#endif
diff --git a/mpeg2enc/mtable.h b/mpeg2enc/mtable.h
new file mode 100644 (file)
index 0000000..0041a81
--- /dev/null
@@ -0,0 +1,4097 @@
+const unsigned char motion_lookup[256][256] = {
+{  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16, 
+ 17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32, 
+ 33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48, 
+ 49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64, 
+ 65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80, 
+ 81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96, 
+ 97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 
+113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 
+129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 
+145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 
+161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 
+177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 
+193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 
+209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 
+225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 
+241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255},
+{  1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15, 
+ 16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31, 
+ 32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47, 
+ 48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63, 
+ 64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79, 
+ 80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95, 
+ 96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 
+240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254},
+{  2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14, 
+ 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30, 
+ 31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46, 
+ 47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62, 
+ 63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78, 
+ 79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94, 
+ 95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 
+111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 
+127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 
+143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 
+159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 
+175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 
+191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 
+207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 
+223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 
+239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253},
+{  3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13, 
+ 14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29, 
+ 30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45, 
+ 46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 
+ 62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77, 
+ 78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93, 
+ 94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 
+110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 
+126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 
+142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 
+158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 
+174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 
+190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 
+206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 
+222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 
+238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252},
+{  4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12, 
+ 13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28, 
+ 29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44, 
+ 45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60, 
+ 61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76, 
+ 77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92, 
+ 93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 
+109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 
+141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 
+157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 
+173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 
+189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 
+205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 
+221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 
+237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251},
+{  5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11, 
+ 12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27, 
+ 28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43, 
+ 44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59, 
+ 60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75, 
+ 76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91, 
+ 92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 
+108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 
+124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 
+140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 
+156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 
+172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 
+188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 
+204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 
+220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 
+236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250},
+{  6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10, 
+ 11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26, 
+ 27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42, 
+ 43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58, 
+ 59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74, 
+ 75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90, 
+ 91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 
+107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 
+123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 
+155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 
+171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 
+187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 
+203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 
+219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 
+235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249},
+{  7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9, 
+ 10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 
+ 26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41, 
+ 42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57, 
+ 58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73, 
+ 74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89, 
+ 90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 
+106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 
+122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 
+138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 
+154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 
+170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 
+186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 
+202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 
+218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 
+234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248},
+{  8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8, 
+  9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24, 
+ 25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40, 
+ 41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56, 
+ 57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72, 
+ 73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88, 
+ 89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 
+105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 
+121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 
+137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 
+153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 
+169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 
+185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 
+201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 
+217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 
+233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247},
+{  9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7, 
+  8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23, 
+ 24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39, 
+ 40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55, 
+ 56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71, 
+ 72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87, 
+ 88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 
+104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 
+120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 
+136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 
+168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 
+184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 
+200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 
+216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 
+232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246},
+{ 10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6, 
+  7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22, 
+ 23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38, 
+ 39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54, 
+ 55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70, 
+ 71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86, 
+ 87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 
+103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 
+119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 
+135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 
+151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 
+167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 
+183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 
+199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 
+215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 
+231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245},
+{ 11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5, 
+  6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21, 
+ 22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37, 
+ 38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53, 
+ 54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69, 
+ 70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85, 
+ 86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 
+102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 
+118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 
+134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 
+150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 
+166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 
+182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 
+198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 
+214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 
+230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244},
+{ 12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4, 
+  5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20, 
+ 21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36, 
+ 37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52, 
+ 53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68, 
+ 69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84, 
+ 85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 
+101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 
+117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 
+133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 
+149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 
+165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 
+181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 
+197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 
+213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 
+229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243},
+{ 13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3, 
+  4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19, 
+ 20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35, 
+ 36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 
+ 52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67, 
+ 68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83, 
+ 84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 
+100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 
+116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 
+132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 
+148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 
+164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 
+180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 
+196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 
+212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 
+228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242},
+{ 14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2, 
+  3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18, 
+ 19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34, 
+ 35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50, 
+ 51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66, 
+ 67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82, 
+ 83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98, 
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 
+115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 
+131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 
+147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 
+163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 
+179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 
+195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 
+211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 
+227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241},
+{ 15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1, 
+  2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17, 
+ 18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33, 
+ 34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49, 
+ 50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65, 
+ 66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81, 
+ 82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97, 
+ 98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 
+130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 
+146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 
+162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 
+178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 
+194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 
+210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 
+226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240},
+{ 16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0, 
+  1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16, 
+ 17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32, 
+ 33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48, 
+ 49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64, 
+ 65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80, 
+ 81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96, 
+ 97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 
+113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 
+129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 
+145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 
+161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 
+177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 
+193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 
+209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 
+225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239},
+{ 17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1, 
+  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15, 
+ 16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31, 
+ 32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47, 
+ 48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63, 
+ 64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79, 
+ 80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95, 
+ 96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 
+224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238},
+{ 18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2, 
+  1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14, 
+ 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30, 
+ 31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46, 
+ 47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62, 
+ 63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78, 
+ 79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94, 
+ 95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 
+111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 
+127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 
+143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 
+159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 
+175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 
+191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 
+207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 
+223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237},
+{ 19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3, 
+  2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13, 
+ 14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29, 
+ 30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45, 
+ 46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 
+ 62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77, 
+ 78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93, 
+ 94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 
+110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 
+126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 
+142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 
+158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 
+174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 
+190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 
+206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 
+222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236},
+{ 20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4, 
+  3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12, 
+ 13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28, 
+ 29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44, 
+ 45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60, 
+ 61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76, 
+ 77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92, 
+ 93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 
+109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 
+141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 
+157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 
+173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 
+189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 
+205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 
+221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235},
+{ 21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5, 
+  4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11, 
+ 12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27, 
+ 28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43, 
+ 44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59, 
+ 60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75, 
+ 76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91, 
+ 92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 
+108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 
+124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 
+140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 
+156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 
+172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 
+188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 
+204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 
+220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234},
+{ 22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6, 
+  5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10, 
+ 11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26, 
+ 27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42, 
+ 43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58, 
+ 59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74, 
+ 75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90, 
+ 91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 
+107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 
+123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 
+155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 
+171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 
+187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 
+203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 
+219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233},
+{ 23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7, 
+  6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9, 
+ 10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 
+ 26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41, 
+ 42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57, 
+ 58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73, 
+ 74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89, 
+ 90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 
+106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 
+122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 
+138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 
+154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 
+170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 
+186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 
+202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 
+218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232},
+{ 24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8, 
+  7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8, 
+  9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24, 
+ 25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40, 
+ 41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56, 
+ 57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72, 
+ 73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88, 
+ 89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 
+105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 
+121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 
+137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 
+153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 
+169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 
+185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 
+201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 
+217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231},
+{ 25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9, 
+  8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7, 
+  8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23, 
+ 24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39, 
+ 40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55, 
+ 56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71, 
+ 72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87, 
+ 88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 
+104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 
+120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 
+136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 
+168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 
+184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 
+200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 
+216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230},
+{ 26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10, 
+  9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6, 
+  7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22, 
+ 23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38, 
+ 39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54, 
+ 55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70, 
+ 71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86, 
+ 87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 
+103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 
+119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 
+135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 
+151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 
+167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 
+183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 
+199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 
+215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229},
+{ 27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11, 
+ 10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5, 
+  6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21, 
+ 22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37, 
+ 38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53, 
+ 54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69, 
+ 70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85, 
+ 86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 
+102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 
+118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 
+134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 
+150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 
+166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 
+182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 
+198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 
+214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228},
+{ 28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12, 
+ 11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4, 
+  5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20, 
+ 21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36, 
+ 37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52, 
+ 53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68, 
+ 69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84, 
+ 85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 
+101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 
+117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 
+133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 
+149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 
+165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 
+181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 
+197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 
+213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227},
+{ 29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13, 
+ 12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3, 
+  4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19, 
+ 20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35, 
+ 36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 
+ 52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67, 
+ 68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83, 
+ 84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 
+100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 
+116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 
+132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 
+148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 
+164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 
+180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 
+196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 
+212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226},
+{ 30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14, 
+ 13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2, 
+  3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18, 
+ 19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34, 
+ 35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50, 
+ 51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66, 
+ 67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82, 
+ 83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98, 
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 
+115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 
+131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 
+147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 
+163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 
+179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 
+195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 
+211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225},
+{ 31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15, 
+ 14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1, 
+  2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17, 
+ 18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33, 
+ 34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49, 
+ 50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65, 
+ 66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81, 
+ 82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97, 
+ 98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 
+130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 
+146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 
+162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 
+178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 
+194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 
+210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224},
+{ 32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16, 
+ 15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0, 
+  1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16, 
+ 17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32, 
+ 33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48, 
+ 49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64, 
+ 65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80, 
+ 81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96, 
+ 97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 
+113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 
+129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 
+145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 
+161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 
+177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 
+193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 
+209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223},
+{ 33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17, 
+ 16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1, 
+  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15, 
+ 16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31, 
+ 32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47, 
+ 48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63, 
+ 64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79, 
+ 80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95, 
+ 96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 
+208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222},
+{ 34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18, 
+ 17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2, 
+  1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14, 
+ 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30, 
+ 31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46, 
+ 47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62, 
+ 63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78, 
+ 79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94, 
+ 95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 
+111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 
+127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 
+143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 
+159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 
+175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 
+191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 
+207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221},
+{ 35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19, 
+ 18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3, 
+  2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13, 
+ 14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29, 
+ 30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45, 
+ 46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 
+ 62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77, 
+ 78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93, 
+ 94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 
+110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 
+126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 
+142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 
+158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 
+174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 
+190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 
+206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220},
+{ 36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20, 
+ 19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4, 
+  3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12, 
+ 13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28, 
+ 29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44, 
+ 45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60, 
+ 61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76, 
+ 77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92, 
+ 93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 
+109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 
+141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 
+157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 
+173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 
+189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 
+205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219},
+{ 37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21, 
+ 20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5, 
+  4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11, 
+ 12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27, 
+ 28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43, 
+ 44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59, 
+ 60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75, 
+ 76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91, 
+ 92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 
+108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 
+124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 
+140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 
+156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 
+172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 
+188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 
+204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218},
+{ 38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22, 
+ 21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6, 
+  5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10, 
+ 11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26, 
+ 27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42, 
+ 43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58, 
+ 59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74, 
+ 75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90, 
+ 91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 
+107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 
+123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 
+155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 
+171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 
+187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 
+203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217},
+{ 39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23, 
+ 22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7, 
+  6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9, 
+ 10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 
+ 26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41, 
+ 42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57, 
+ 58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73, 
+ 74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89, 
+ 90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 
+106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 
+122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 
+138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 
+154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 
+170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 
+186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 
+202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216},
+{ 40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24, 
+ 23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8, 
+  7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8, 
+  9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24, 
+ 25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40, 
+ 41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56, 
+ 57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72, 
+ 73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88, 
+ 89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 
+105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 
+121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 
+137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 
+153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 
+169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 
+185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 
+201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215},
+{ 41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25, 
+ 24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9, 
+  8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7, 
+  8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23, 
+ 24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39, 
+ 40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55, 
+ 56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71, 
+ 72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87, 
+ 88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 
+104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 
+120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 
+136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 
+168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 
+184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 
+200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214},
+{ 42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26, 
+ 25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10, 
+  9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6, 
+  7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22, 
+ 23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38, 
+ 39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54, 
+ 55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70, 
+ 71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86, 
+ 87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 
+103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 
+119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 
+135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 
+151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 
+167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 
+183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 
+199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213},
+{ 43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27, 
+ 26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11, 
+ 10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5, 
+  6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21, 
+ 22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37, 
+ 38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53, 
+ 54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69, 
+ 70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85, 
+ 86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 
+102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 
+118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 
+134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 
+150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 
+166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 
+182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 
+198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212},
+{ 44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28, 
+ 27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12, 
+ 11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4, 
+  5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20, 
+ 21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36, 
+ 37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52, 
+ 53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68, 
+ 69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84, 
+ 85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 
+101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 
+117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 
+133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 
+149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 
+165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 
+181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 
+197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211},
+{ 45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29, 
+ 28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13, 
+ 12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3, 
+  4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19, 
+ 20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35, 
+ 36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 
+ 52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67, 
+ 68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83, 
+ 84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 
+100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 
+116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 
+132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 
+148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 
+164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 
+180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 
+196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210},
+{ 46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30, 
+ 29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14, 
+ 13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2, 
+  3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18, 
+ 19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34, 
+ 35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50, 
+ 51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66, 
+ 67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82, 
+ 83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98, 
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 
+115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 
+131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 
+147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 
+163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 
+179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 
+195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209},
+{ 47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31, 
+ 30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15, 
+ 14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1, 
+  2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17, 
+ 18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33, 
+ 34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49, 
+ 50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65, 
+ 66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81, 
+ 82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97, 
+ 98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 
+130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 
+146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 
+162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 
+178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 
+194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208},
+{ 48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32, 
+ 31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16, 
+ 15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0, 
+  1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16, 
+ 17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32, 
+ 33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48, 
+ 49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64, 
+ 65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80, 
+ 81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96, 
+ 97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 
+113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 
+129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 
+145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 
+161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 
+177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 
+193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207},
+{ 49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33, 
+ 32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17, 
+ 16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1, 
+  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15, 
+ 16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31, 
+ 32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47, 
+ 48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63, 
+ 64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79, 
+ 80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95, 
+ 96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 
+192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206},
+{ 50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34, 
+ 33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18, 
+ 17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2, 
+  1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14, 
+ 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30, 
+ 31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46, 
+ 47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62, 
+ 63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78, 
+ 79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94, 
+ 95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 
+111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 
+127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 
+143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 
+159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 
+175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 
+191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205},
+{ 51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35, 
+ 34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19, 
+ 18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3, 
+  2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13, 
+ 14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29, 
+ 30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45, 
+ 46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 
+ 62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77, 
+ 78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93, 
+ 94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 
+110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 
+126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 
+142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 
+158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 
+174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 
+190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204},
+{ 52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36, 
+ 35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20, 
+ 19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4, 
+  3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12, 
+ 13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28, 
+ 29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44, 
+ 45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60, 
+ 61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76, 
+ 77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92, 
+ 93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 
+109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 
+141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 
+157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 
+173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 
+189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203},
+{ 53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37, 
+ 36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21, 
+ 20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5, 
+  4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11, 
+ 12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27, 
+ 28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43, 
+ 44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59, 
+ 60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75, 
+ 76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91, 
+ 92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 
+108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 
+124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 
+140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 
+156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 
+172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 
+188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202},
+{ 54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38, 
+ 37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22, 
+ 21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6, 
+  5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10, 
+ 11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26, 
+ 27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42, 
+ 43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58, 
+ 59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74, 
+ 75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90, 
+ 91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 
+107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 
+123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 
+155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 
+171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 
+187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201},
+{ 55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39, 
+ 38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23, 
+ 22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7, 
+  6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9, 
+ 10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 
+ 26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41, 
+ 42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57, 
+ 58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73, 
+ 74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89, 
+ 90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 
+106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 
+122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 
+138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 
+154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 
+170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 
+186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200},
+{ 56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40, 
+ 39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24, 
+ 23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8, 
+  7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8, 
+  9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24, 
+ 25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40, 
+ 41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56, 
+ 57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72, 
+ 73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88, 
+ 89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 
+105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 
+121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 
+137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 
+153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 
+169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 
+185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199},
+{ 57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41, 
+ 40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25, 
+ 24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9, 
+  8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7, 
+  8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23, 
+ 24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39, 
+ 40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55, 
+ 56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71, 
+ 72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87, 
+ 88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 
+104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 
+120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 
+136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 
+168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 
+184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198},
+{ 58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42, 
+ 41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26, 
+ 25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10, 
+  9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6, 
+  7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22, 
+ 23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38, 
+ 39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54, 
+ 55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70, 
+ 71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86, 
+ 87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 
+103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 
+119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 
+135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 
+151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 
+167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 
+183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197},
+{ 59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43, 
+ 42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27, 
+ 26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11, 
+ 10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5, 
+  6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21, 
+ 22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37, 
+ 38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53, 
+ 54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69, 
+ 70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85, 
+ 86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 
+102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 
+118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 
+134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 
+150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 
+166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 
+182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196},
+{ 60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44, 
+ 43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28, 
+ 27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12, 
+ 11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4, 
+  5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20, 
+ 21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36, 
+ 37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52, 
+ 53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68, 
+ 69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84, 
+ 85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 
+101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 
+117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 
+133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 
+149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 
+165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 
+181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195},
+{ 61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45, 
+ 44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29, 
+ 28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13, 
+ 12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3, 
+  4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19, 
+ 20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35, 
+ 36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 
+ 52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67, 
+ 68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83, 
+ 84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 
+100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 
+116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 
+132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 
+148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 
+164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 
+180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194},
+{ 62,  61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46, 
+ 45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30, 
+ 29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14, 
+ 13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2, 
+  3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18, 
+ 19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34, 
+ 35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50, 
+ 51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66, 
+ 67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82, 
+ 83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98, 
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 
+115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 
+131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 
+147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 
+163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 
+179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193},
+{ 63,  62,  61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47, 
+ 46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31, 
+ 30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15, 
+ 14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1, 
+  2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17, 
+ 18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33, 
+ 34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49, 
+ 50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65, 
+ 66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81, 
+ 82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97, 
+ 98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 
+130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 
+146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 
+162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 
+178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192},
+{ 64,  63,  62,  61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48, 
+ 47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32, 
+ 31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16, 
+ 15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0, 
+  1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16, 
+ 17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32, 
+ 33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48, 
+ 49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64, 
+ 65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80, 
+ 81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96, 
+ 97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 
+113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 
+129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 
+145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 
+161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 
+177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191},
+{ 65,  64,  63,  62,  61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49, 
+ 48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33, 
+ 32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17, 
+ 16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1, 
+  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15, 
+ 16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31, 
+ 32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47, 
+ 48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63, 
+ 64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79, 
+ 80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95, 
+ 96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 
+176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190},
+{ 66,  65,  64,  63,  62,  61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50, 
+ 49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34, 
+ 33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18, 
+ 17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2, 
+  1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14, 
+ 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30, 
+ 31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46, 
+ 47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62, 
+ 63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78, 
+ 79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94, 
+ 95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 
+111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 
+127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 
+143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 
+159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 
+175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189},
+{ 67,  66,  65,  64,  63,  62,  61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51, 
+ 50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35, 
+ 34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19, 
+ 18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3, 
+  2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13, 
+ 14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29, 
+ 30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45, 
+ 46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 
+ 62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77, 
+ 78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93, 
+ 94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 
+110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 
+126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 
+142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 
+158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 
+174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188},
+{ 68,  67,  66,  65,  64,  63,  62,  61,  60,  59,  58,  57,  56,  55,  54,  53,  52, 
+ 51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36, 
+ 35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20, 
+ 19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4, 
+  3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12, 
+ 13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28, 
+ 29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44, 
+ 45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60, 
+ 61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76, 
+ 77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92, 
+ 93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 
+109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 
+141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 
+157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 
+173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187},
+{ 69,  68,  67,  66,  65,  64,  63,  62,  61,  60,  59,  58,  57,  56,  55,  54,  53, 
+ 52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37, 
+ 36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21, 
+ 20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5, 
+  4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11, 
+ 12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27, 
+ 28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43, 
+ 44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59, 
+ 60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75, 
+ 76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91, 
+ 92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 
+108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 
+124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 
+140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 
+156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 
+172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186},
+{ 70,  69,  68,  67,  66,  65,  64,  63,  62,  61,  60,  59,  58,  57,  56,  55,  54, 
+ 53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38, 
+ 37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22, 
+ 21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6, 
+  5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10, 
+ 11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26, 
+ 27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42, 
+ 43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58, 
+ 59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74, 
+ 75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90, 
+ 91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 
+107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 
+123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 
+155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 
+171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185},
+{ 71,  70,  69,  68,  67,  66,  65,  64,  63,  62,  61,  60,  59,  58,  57,  56,  55, 
+ 54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39, 
+ 38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23, 
+ 22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7, 
+  6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9, 
+ 10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 
+ 26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41, 
+ 42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57, 
+ 58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73, 
+ 74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89, 
+ 90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 
+106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 
+122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 
+138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 
+154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 
+170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184},
+{ 72,  71,  70,  69,  68,  67,  66,  65,  64,  63,  62,  61,  60,  59,  58,  57,  56, 
+ 55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40, 
+ 39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24, 
+ 23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8, 
+  7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8, 
+  9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24, 
+ 25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40, 
+ 41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56, 
+ 57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72, 
+ 73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88, 
+ 89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 
+105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 
+121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 
+137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 
+153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 
+169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183},
+{ 73,  72,  71,  70,  69,  68,  67,  66,  65,  64,  63,  62,  61,  60,  59,  58,  57, 
+ 56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41, 
+ 40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25, 
+ 24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9, 
+  8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7, 
+  8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23, 
+ 24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39, 
+ 40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55, 
+ 56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71, 
+ 72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87, 
+ 88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 
+104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 
+120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 
+136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 
+168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182},
+{ 74,  73,  72,  71,  70,  69,  68,  67,  66,  65,  64,  63,  62,  61,  60,  59,  58, 
+ 57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42, 
+ 41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26, 
+ 25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10, 
+  9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6, 
+  7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22, 
+ 23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38, 
+ 39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54, 
+ 55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70, 
+ 71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86, 
+ 87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 
+103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 
+119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 
+135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 
+151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 
+167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181},
+{ 75,  74,  73,  72,  71,  70,  69,  68,  67,  66,  65,  64,  63,  62,  61,  60,  59, 
+ 58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44,  43, 
+ 42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28,  27, 
+ 26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11, 
+ 10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4,   5, 
+  6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21, 
+ 22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37, 
+ 38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53, 
+ 54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69, 
+ 70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85, 
+ 86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 
+102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 
+118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 
+134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 
+150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 
+166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180},
+{ 76,  75,  74,  73,  72,  71,  70,  69,  68,  67,  66,  65,  64,  63,  62,  61,  60, 
+ 59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45,  44, 
+ 43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29,  28, 
+ 27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13,  12, 
+ 11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3,   4, 
+  5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20, 
+ 21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36, 
+ 37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52, 
+ 53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68, 
+ 69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84, 
+ 85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 
+101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 
+117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 
+133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 
+149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 
+165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179},
+{ 77,  76,  75,  74,  73,  72,  71,  70,  69,  68,  67,  66,  65,  64,  63,  62,  61, 
+ 60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,  45, 
+ 44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30,  29, 
+ 28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14,  13, 
+ 12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2,   3, 
+  4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19, 
+ 20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35, 
+ 36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 
+ 52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67, 
+ 68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83, 
+ 84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 
+100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 
+116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 
+132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 
+148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 
+164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178},
+{ 78,  77,  76,  75,  74,  73,  72,  71,  70,  69,  68,  67,  66,  65,  64,  63,  62, 
+ 61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46, 
+ 45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31,  30, 
+ 29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15,  14, 
+ 13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1,   2, 
+  3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18, 
+ 19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34, 
+ 35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50, 
+ 51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66, 
+ 67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82, 
+ 83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98, 
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 
+115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 
+131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 
+147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 
+163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177},
+{ 79,  78,  77,  76,  75,  74,  73,  72,  71,  70,  69,  68,  67,  66,  65,  64,  63, 
+ 62,  61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47, 
+ 46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32,  31, 
+ 30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16,  15, 
+ 14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0,   1, 
+  2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17, 
+ 18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33, 
+ 34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49, 
+ 50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65, 
+ 66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81, 
+ 82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97, 
+ 98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 
+130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 
+146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 
+162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176},
+{ 80,  79,  78,  77,  76,  75,  74,  73,  72,  71,  70,  69,  68,  67,  66,  65,  64, 
+ 63,  62,  61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48, 
+ 47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33,  32, 
+ 31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17,  16, 
+ 15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1,   0, 
+  1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16, 
+ 17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32, 
+ 33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48, 
+ 49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64, 
+ 65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80, 
+ 81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96, 
+ 97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 
+113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 
+129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 
+145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 
+161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175},
+{ 81,  80,  79,  78,  77,  76,  75,  74,  73,  72,  71,  70,  69,  68,  67,  66,  65, 
+ 64,  63,  62,  61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49, 
+ 48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34,  33, 
+ 32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,  17, 
+ 16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2,   1, 
+  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15, 
+ 16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31, 
+ 32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47, 
+ 48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63, 
+ 64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79, 
+ 80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95, 
+ 96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 
+112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 
+128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 
+144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 
+160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174},
+{ 82,  81,  80,  79,  78,  77,  76,  75,  74,  73,  72,  71,  70,  69,  68,  67,  66, 
+ 65,  64,  63,  62,  61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50, 
+ 49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35,  34, 
+ 33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18, 
+ 17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3,   2, 
+  1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14, 
+ 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30, 
+ 31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46, 
+ 47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62, 
+ 63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78, 
+ 79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94, 
+ 95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 
+111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 
+127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 
+143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 
+159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173},
+{ 83,  82,  81,  80,  79,  78,  77,  76,  75,  74,  73,  72,  71,  70,  69,  68,  67, 
+ 66,  65,  64,  63,  62,  61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51, 
+ 50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36,  35, 
+ 34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19, 
+ 18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4,   3, 
+  2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13, 
+ 14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29, 
+ 30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45, 
+ 46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 
+ 62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77, 
+ 78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93, 
+ 94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 
+110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 
+126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 
+142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 
+158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172},
+{ 84,  83,  82,  81,  80,  79,  78,  77,  76,  75,  74,  73,  72,  71,  70,  69,  68, 
+ 67,  66,  65,  64,  63,  62,  61,  60,  59,  58,  57,  56,  55,  54,  53,  52, 
+ 51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37,  36, 
+ 35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20, 
+ 19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5,   4, 
+  3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12, 
+ 13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28, 
+ 29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44, 
+ 45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60, 
+ 61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76, 
+ 77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92, 
+ 93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 
+109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 
+141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 
+157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171},
+{ 85,  84,  83,  82,  81,  80,  79,  78,  77,  76,  75,  74,  73,  72,  71,  70,  69, 
+ 68,  67,  66,  65,  64,  63,  62,  61,  60,  59,  58,  57,  56,  55,  54,  53, 
+ 52,  51,  50,  49,  48,  47,  46,  45,  44,  43,  42,  41,  40,  39,  38,  37, 
+ 36,  35,  34,  33,  32,  31,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21, 
+ 20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,   8,   7,   6,   5, 
+  4,   3,   2,   1,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11, 
+ 12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27, 
+ 28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43, 
+ 44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59, 
+ 60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75, 
+ 76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91, 
+ 92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 
+108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 
+124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 
+140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 
+156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170},
+{ 86,  85,  84,  83,  82,  81,  80,  79,  78,  77,  76,  75,  74,  73,  72,  71,  70, 
+ 69,  68,  67,  66,  65,  64,  63,  62,  61,  60,  59,  58,  57,  56,  55,  54, 
+ 53,  52,  51, &n