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