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