xref: /original-bsd/sys/vax/vax/ns_cksum.c (revision 69c8e3e7)
1 /*
2  * Copyright (c) 1985, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)ns_cksum.c	7.6 (Berkeley) 12/16/90
8  */
9 
10 #include "sys/param.h"
11 #include "sys/mbuf.h"
12 
13 
14 /*
15  * Checksum routine for Network Systems Protocol Packets (VAX Version).
16  *
17  * This routine is very heavily used in the network
18  * code and should be modified for each CPU to be as fast as possible.
19  */
20 
21 u_short
22 ns_cksum(m, len)
23 	register struct mbuf *m;
24 	register int len;
25 {
26 	register u_short *w;		/* on vax, known to be r9 */
27 	register int sum = 0;		/* on vax, known to be r8 */
28 	register int low = 0;		/* on vax, known to be r7 */
29 	register int mlen = low;	/* want 0, shuts lint up about low */
30 
31 	for (;;) {
32 		/*
33 		 * Each trip around loop adds in
34 		 * word from one mbuf segment.
35 		 */
36 		w = mtod(m, u_short *);
37 		if (mlen == -1) {
38 			/*
39 			 * There is a byte left from the last segment;
40 			 * add it into the checksum.  Don't have to worry
41 			 * about a carry-out here because we make sure
42 			 * that high part of (32 bit) sum is small below.
43 			 */
44 			sum += *(u_char *)w << 8;
45 			sum += sum;
46 			w = (u_short *)((char *)w + 1);
47 			mlen = m->m_len - 1;
48 			len--;
49 		} else
50 			mlen = m->m_len;
51 		m = m->m_next;
52 		if (len < mlen)
53 			mlen = len;
54 		len -= mlen;
55 		/*
56 		 * Force to long boundary so we do longword aligned
57 		 * memory operations.  It is too hard to do byte
58 		 * adjustment, do only word adjustment.
59 		 */
60 		if (((int)w&0x2) && mlen >= 2) {
61 			sum += *w++;
62 			sum += sum;
63 			mlen -= 2;
64 		}
65 		/*
66 		 *
67 		 * We can do a 16 bit ones complement sum using
68 		 * 32 bit arithmetic registers for adding,
69 		 * with carries from the low added
70 		 * into the high (by normal carry-chaining)
71 		 * so long as we fold back before 16 carries have occured.
72 		 *
73 		 */
74 		while ((mlen -= 32) >= 0) {
75 			/*asm("bicpsw $1");		 clears carry */
76 #undef ADD
77 #define ADD asm("movw (r9)+,r7")asm("addl2 r7,r8")asm("addl2 r8,r8")
78 #define FOLD { asm("ashl $-16,r8,r0")asm(" addw2 r0,r8"); \
79 		  asm("adwc $0,r8")asm(" movzwl r8,r8"); }
80 			FOLD;
81 			ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD;
82 			FOLD;
83 			ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD;
84 		}
85 		mlen += 32;
86 		while ((mlen -= 8) >= 0) {
87 			/*asm("bicpsw $1");		 clears carry */
88 			FOLD;
89 			ADD; ADD; ADD; ADD;
90 		}
91 		mlen += 8;
92 		/*
93 		 * Now eliminate the possibility of carry-out's by
94 		 * folding back to a 16 bit number (adding high and
95 		 * low parts together.)  Then mop up trailing words
96 		 * and maybe an odd byte.
97 		 */
98 		FOLD;
99 		while ((mlen -= 2) >= 0) {
100 			ADD;
101 		}
102 		if (mlen == -1) {
103 			sum += *(u_char *)w;
104 		}
105 		if (len == 0)
106 			break;
107 		/*
108 		 * Locate the next block with some data.
109 		 * If there is a word split across a boundary we
110 		 * will wrap to the top with mlen == -1 and
111 		 * then add it in shifted appropriately.
112 		 */
113 		for (;;) {
114 			if (m == 0) {
115 				printf("idpcksum: out of data\n");
116 				goto done;
117 			}
118 			if (m->m_len)
119 				break;
120 			m = m->m_next;
121 		}
122 	}
123 done:
124 	/*
125 	 * Add together high and low parts of sum
126 	 * and carry to get cksum.
127 	 * Have to be careful to not drop the last
128 	 * carry here.
129 	 */
130 	FOLD;
131 
132 	if(sum==0xffff) sum = 0;
133 	return (sum);
134 }
135