1480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#!/usr/bin/env perl
2480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
3480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# ====================================================================
4480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# Written by David Mosberger <David.Mosberger@acm.org> based on the
5480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# Itanium optimized Crypto code which was released by HP Labs at
6480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# http://www.hpl.hp.com/research/linux/crypto/.
7480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
8480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
9480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
10480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# Permission is hereby granted, free of charge, to any person obtaining
11480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# a copy of this software and associated documentation files (the
12480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# "Software"), to deal in the Software without restriction, including
13480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# without limitation the rights to use, copy, modify, merge, publish,
14480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# distribute, sublicense, and/or sell copies of the Software, and to
15480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# permit persons to whom the Software is furnished to do so, subject to
16480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# the following conditions:
17480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
18480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# The above copyright notice and this permission notice shall be
19480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# included in all copies or substantial portions of the Software.
20480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
21480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
28480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
29480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
30480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
31480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# This is a little helper program which generates a software-pipelined
32480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# for RC4 encryption.  The basic algorithm looks like this:
33480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
34480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#   for (counter = 0; counter < len; ++counter)
35480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     {
36480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#       in = inp[counter];
37480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#       SI = S[I];
38480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#       J = (SI + J) & 0xff;
39480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#       SJ = S[J];
40480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#       T = (SI + SJ) & 0xff;
41480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#       S[I] = SJ, S[J] = SI;
42480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#       ST = S[T];
43480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#       outp[counter] = in ^ ST;
44480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#       I = (I + 1) & 0xff;
45480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     }
46480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
47480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# Pipelining this loop isn't easy, because the stores to the S[] array
48480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# need to be observed in the right order.  The loop generated by the
49480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# code below has the following pipeline diagram:
50480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
51480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#      cycle
52480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |15 |16 |17 |
53480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# iter
54480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#   1: xxx LDI xxx xxx xxx LDJ xxx SWP xxx LDT xxx xxx
55480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#   2:             xxx LDI xxx xxx xxx LDJ xxx SWP xxx LDT xxx xxx
56480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#   3:                         xxx LDI xxx xxx xxx LDJ xxx SWP xxx LDT xxx xxx
57480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
58480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#   where:
59480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# 	LDI = load of S[I]
60480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# 	LDJ = load of S[J]
61480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# 	SWP = swap of S[I] and S[J]
62480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# 	LDT = load of S[T]
63480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
64480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# Note that in the above diagram, the major trouble-spot is that LDI
65480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# of the 2nd iteration is performed BEFORE the SWP of the first
66480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# iteration.  Fortunately, this is easy to detect (I of the 1st
67480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# iteration will be equal to J of the 2nd iteration) and when this
68480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# happens, we simply forward the proper value from the 1st iteration
69480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# to the 2nd one.  The proper value in this case is simply the value
70480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# of S[I] from the first iteration (thanks to the fact that SWP
71480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# simply swaps the contents of S[I] and S[J]).
72480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
73480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# Another potential trouble-spot is in cycle 7, where SWP of the 1st
74480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# iteration issues at the same time as the LDI of the 3rd iteration.
75480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# However, thanks to IA-64 execution semantics, this can be taken
76480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# care of simply by placing LDI later in the instruction-group than
77480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# SWP.  IA-64 CPUs will automatically forward the value if they
78480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# detect that the SWP and LDI are accessing the same memory-location.
79480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
80480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# The core-loop that can be pipelined then looks like this (annotated
81480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# with McKinley/Madison issue port & latency numbers, assuming L1
82480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# cache hits for the most part):
83480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
84480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# operation:	    instruction:		    issue-ports:  latency
85480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# ------------------  -----------------------------   ------------- -------
86480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
87480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# Data = *inp++       ld1 data = [inp], 1             M0-M1         1 cyc     c0
88480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     shladd Iptr = I, KeyTable, 3    M0-M3, I0, I1 1 cyc
89480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# I = (I + 1) & 0xff  padd1 nextI = I, one            M0-M3, I0, I1 3 cyc
90480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     ;;
91480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# SI = S[I]           ld8 SI = [Iptr]                 M0-M1         1 cyc     c1 * after SWAP!
92480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     ;;
93480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     cmp.eq.unc pBypass = I, J                                  * after J is valid!
94480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# J = SI + J          add J = J, SI                   M0-M3, I0, I1 1 cyc     c2
95480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     (pBypass) br.cond.spnt Bypass
96480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     ;;
97480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# ---------------------------------------------------------------------------------------
98480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# J = J & 0xff        zxt1 J = J                      I0, I1, 1 cyc           c3
99480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     ;;
100480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     shladd Jptr = J, KeyTable, 3    M0-M3, I0, I1 1 cyc     c4
101480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     ;;
102480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# SJ = S[J]           ld8 SJ = [Jptr]                 M0-M1         1 cyc     c5
103480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     ;;
104480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# ---------------------------------------------------------------------------------------
105480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# T = (SI + SJ)       add T = SI, SJ                  M0-M3, I0, I1 1 cyc     c6
106480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     ;;
107480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# T = T & 0xff        zxt1 T = T                      I0, I1        1 cyc
108480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# S[I] = SJ           st8 [Iptr] = SJ                 M2-M3                   c7
109480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# S[J] = SI           st8 [Jptr] = SI                 M2-M3
110480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     ;;
111480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     shladd Tptr = T, KeyTable, 3    M0-M3, I0, I1 1 cyc     c8
112480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     ;;
113480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# ---------------------------------------------------------------------------------------
114480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# T = S[T]            ld8 T = [Tptr]                  M0-M1         1 cyc     c9
115480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     ;;
116480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# data ^= T           xor data = data, T              M0-M3, I0, I1 1 cyc     c10
117480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     ;;
118480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# *out++ = Data ^ T   dep word = word, data, 8, POS   I0, I1        1 cyc     c11
119480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#                     ;;
120480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# ---------------------------------------------------------------------------------------
121480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
122480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# There are several points worth making here:
123480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
124480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#   - Note that due to the bypass/forwarding-path, the first two
125480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     phases of the loop are strangly mingled together.  In
126480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     particular, note that the first stage of the pipeline is
127480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     using the value of "J", as calculated by the second stage.
128480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#   - Each bundle-pair will have exactly 6 instructions.
129480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#   - Pipelined, the loop can execute in 3 cycles/iteration and
130480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     4 stages.  However, McKinley/Madison can issue "st1" to
131480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     the same bank at a rate of at most one per 4 cycles.  Thus,
132480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     instead of storing each byte, we accumulate them in a word
133480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     and then write them back at once with a single "st8" (this
134480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     implies that the setup code needs to ensure that the output
135480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     buffer is properly aligned, if need be, by encoding the
136480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     first few bytes separately).
137480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#   - There is no space for a "br.ctop" instruction.  For this
138480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     reason we can't use module-loop support in IA-64 and have
139480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     to do a traditional, purely software-pipelined loop.
140480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#   - We can't replace any of the remaining "add/zxt1" pairs with
141480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     "padd1" because the latency for that instruction is too high
142480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     and would push the loop to the point where more bypasses
143480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     would be needed, which we don't have space for.
144480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#   - The above loop runs at around 3.26 cycles/byte, or roughly
145480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     440 MByte/sec on a 1.5GHz Madison.  This is well below the
146480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     system bus bandwidth and hence with judicious use of
147480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     "lfetch" this loop can run at (almost) peak speed even when
148480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     the input and output data reside in memory.  The
149480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     max. latency that can be tolerated is (PREFETCH_DISTANCE *
150480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     L2_LINE_SIZE * 3 cyc), or about 384 cycles assuming (at
151480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     least) 1-ahead prefetching of 128 byte cache-lines.  Note
152480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     that we do NOT prefetch into L1, since that would only
153480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     interfere with the S[] table values stored there.  This is
154480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     acceptable because there is a 10 cycle latency between
155480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     load and first use of the input data.
156480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#   - We use a branch to out-of-line bypass-code of cycle-pressure:
157480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     we calculate the next J, check for the need to activate the
158480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     bypass path, and activate the bypass path ALL IN THE SAME
159480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     CYCLE.  If we didn't have these constraints, we could do
160480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     the bypass with a simple conditional move instruction.
161480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     Fortunately, the bypass paths get activated relatively
162480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     infrequently, so the extra branches don't cost all that much
163480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     (about 0.04 cycles/byte, measured on a 16396 byte file with
164480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#     random input data).
165480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
166480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
167480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$phases = 4;		# number of stages/phases in the pipelined-loop
168480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$unroll_count = 6;	# number of times we unrolled it
169480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$pComI = (1 << 0);
170480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$pComJ = (1 << 1);
171480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$pComT = (1 << 2);
172480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$pOut  = (1 << 3);
173480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
174480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$NData = 4;
175480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$NIP = 3;
176480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$NJP = 2;
177480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$NI = 2;
178480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$NSI = 3;
179480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$NSJ = 2;
180480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$NT = 2;
181480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$NOutWord = 2;
182480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
183480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
184480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# $threshold is the minimum length before we attempt to use the
185480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# big software-pipelined loop.  It MUST be greater-or-equal
186480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# to:
187480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#  		PHASES * (UNROLL_COUNT + 1) + 7
188480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
189480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# The "+ 7" comes from the fact we may have to encode up to
190480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#   7 bytes separately before the output pointer is aligned.
191480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#
192480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$threshold = (3 * ($phases * ($unroll_count + 1)) + 7);
193480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
194480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub I {
195480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local *code = shift;
196480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local $format = shift;
197480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $code .= sprintf ("\t\t".$format."\n", @_);
198480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
199480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
200480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub P {
201480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local *code = shift;
202480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local $format = shift;
203480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $code .= sprintf ($format."\n", @_);
204480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
205480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
206480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub STOP {
207480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local *code = shift;
208480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $code .=<<___;
209480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		;;
210480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___
211480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
212480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
213480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgsub emit_body {
214480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local *c = shift;
215480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local *bypass = shift;
216480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local ($iteration, $p) = @_;
217480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
218480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local $i0 = $iteration;
219480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local $i1 = $iteration - 1;
220480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local $i2 = $iteration - 2;
221480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local $i3 = $iteration - 3;
222480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local $iw0 = ($iteration - 3) / 8;
223480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local $iw1 = ($iteration > 3) ? ($iteration - 4) / 8 : 1;
224480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local $byte_num = ($iteration - 3) % 8;
225480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local $label = $iteration + 1;
226480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local $pAny = ($p & 0xf) == 0xf;
227480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    local $pByp = (($p & $pComI) && ($iteration > 0));
228480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
229480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $c.=<<___;
230480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org//////////////////////////////////////////////////
231480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___
232480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
233480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    if (($p & 0xf) == 0) {
234480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	$c.="#ifdef HOST_IS_BIG_ENDIAN\n";
235480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	&I(\$c,"shr.u	OutWord[%u] = OutWord[%u], 32;;",
236480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				$iw1 % $NOutWord, $iw1 % $NOutWord);
237480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	$c.="#endif\n";
238480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	&I(\$c, "st4 [OutPtr] = OutWord[%u], 4", $iw1 % $NOutWord);
239480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	return;
240480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    }
241480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
242480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    # Cycle 0
243480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "{ .mmi")					      if ($pAny);
244480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "ld1    Data[%u] = [InPtr], 1", $i0 % $NData)     if ($p & $pComI);
245480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "padd1  I[%u] = One, I[%u]", $i0 % $NI, $i1 % $NI)if ($p & $pComI);
246480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "zxt1   J = J")				      if ($p & $pComJ);
247480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "}")					      if ($pAny);
248480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "{ .mmi")					      if ($pAny);
249480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "LKEY   T[%u] = [T[%u]]", $i1 % $NT, $i1 % $NT)   if ($p & $pOut);
250480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "add    T[%u] = SI[%u], SJ[%u]",
251480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org       $i0 % $NT, $i2 % $NSI, $i1 % $NSJ)		      if ($p & $pComT);
252480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "KEYADDR(IPr[%u], I[%u])", $i0 % $NIP, $i1 % $NI) if ($p & $pComI);
253480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "}")					      if ($pAny);
254480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &STOP(\$c);
255480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
256480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    # Cycle 1
257480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "{ .mmi")					      if ($pAny);
258480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "SKEY   [IPr[%u]] = SJ[%u]", $i2 % $NIP, $i1%$NSJ)if ($p & $pComT);
259480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "SKEY   [JP[%u]] = SI[%u]", $i1 % $NJP, $i2%$NSI) if ($p & $pComT);
260480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "zxt1   T[%u] = T[%u]", $i0 % $NT, $i0 % $NT)     if ($p & $pComT);
261480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "}")					      if ($pAny);
262480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "{ .mmi")					      if ($pAny);
263480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "LKEY   SI[%u] = [IPr[%u]]", $i0 % $NSI, $i0%$NIP)if ($p & $pComI);
264480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "KEYADDR(JP[%u], J)", $i0 % $NJP)		      if ($p & $pComJ);
265480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "xor    Data[%u] = Data[%u], T[%u]",
266480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org       $i3 % $NData, $i3 % $NData, $i1 % $NT)		      if ($p & $pOut);
267480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "}")					      if ($pAny);
268480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &STOP(\$c);
269480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
270480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    # Cycle 2
271480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "{ .mmi")					      if ($pAny);
272480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "LKEY   SJ[%u] = [JP[%u]]", $i0 % $NSJ, $i0%$NJP) if ($p & $pComJ);
273480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "cmp.eq pBypass, p0 = I[%u], J", $i1 % $NI)	      if ($pByp);
274480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "dep OutWord[%u] = Data[%u], OutWord[%u], BYTE_POS(%u), 8",
275480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org       $iw0%$NOutWord, $i3%$NData, $iw1%$NOutWord, $byte_num) if ($p & $pOut);
276480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "}")					      if ($pAny);
277480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "{ .mmb")					      if ($pAny);
278480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "add    J = J, SI[%u]", $i0 % $NSI)		      if ($p & $pComI);
279480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "KEYADDR(T[%u], T[%u])", $i0 % $NT, $i0 % $NT)    if ($p & $pComT);
280480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &P(\$c, "(pBypass)\tbr.cond.spnt.many .rc4Bypass%u",$label)if ($pByp);
281480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &I(\$c, "}") if ($pAny);
282480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &STOP(\$c);
283480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
284480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &P(\$c, ".rc4Resume%u:", $label)			      if ($pByp);
285480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    if ($byte_num == 0 && $iteration >= $phases) {
286480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	&I(\$c, "st8 [OutPtr] = OutWord[%u], 8",
287480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	   $iw1 % $NOutWord)				      if ($p & $pOut);
288480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	if ($iteration == (1 + $unroll_count) * $phases - 1) {
289480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	    if ($unroll_count == 6) {
290480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		&I(\$c, "mov OutWord[%u] = OutWord[%u]",
291480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		   $iw1 % $NOutWord, $iw0 % $NOutWord);
292480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	    }
293480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	    &I(\$c, "lfetch.nt1 [InPrefetch], %u",
294480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	       $unroll_count * $phases);
295480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	    &I(\$c, "lfetch.excl.nt1 [OutPrefetch], %u",
296480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	       $unroll_count * $phases);
297480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	    &I(\$c, "br.cloop.sptk.few .rc4Loop");
298480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
299480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    }
300480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
301480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    if ($pByp) {
302480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	&P(\$bypass, ".rc4Bypass%u:", $label);
303480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	&I(\$bypass, "sub J = J, SI[%u]", $i0 % $NSI);
304480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	&I(\$bypass, "nop 0");
305480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	&I(\$bypass, "nop 0");
306480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	&I(\$bypass, ";;");
307480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	&I(\$bypass, "add J = J, SI[%u]", $i1 % $NSI);
308480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	&I(\$bypass, "mov SI[%u] = SI[%u]", $i0 % $NSI, $i1 % $NSI);
309480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	&I(\$bypass, "br.sptk.many .rc4Resume%u\n", $label);
310480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	&I(\$bypass, ";;");
311480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    }
312480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
313480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
314480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$code=<<___;
315480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.ident \"rc4-ia64.s, version 3.0\"
316480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.ident \"Copyright (c) 2005 Hewlett-Packard Development Company, L.P.\"
317480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
318480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define LCSave		r8
319480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define PRSave		r9
320480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
321480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org/* Inputs become invalid once rotation begins!  */
322480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
323480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define StateTable	in0
324480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define DataLen		in1
325480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define InputBuffer	in2
326480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define OutputBuffer	in3
327480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
328480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define KTable		r14
329480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define J		r15
330480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define InPtr		r16
331480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define OutPtr		r17
332480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define InPrefetch	r18
333480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define OutPrefetch	r19
334480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define One		r20
335480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define LoopCount	r21
336480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define Remainder	r22
337480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define IFinal		r23
338480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define EndPtr		r24
339480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
340480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define tmp0		r25
341480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define tmp1		r26
342480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
343480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define pBypass		p6
344480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define pDone		p7
345480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define pSmall		p8
346480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define pAligned	p9
347480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define pUnaligned	p10
348480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
349480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define pComputeI	pPhase[0]
350480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define pComputeJ	pPhase[1]
351480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define pComputeT	pPhase[2]
352480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define pOutput		pPhase[3]
353480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
354480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define RetVal		r8
355480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define L_OK		p7
356480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define L_NOK		p8
357480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
358480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define	_NINPUTS	4
359480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define	_NOUTPUT	0
360480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
361480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define	_NROTATE	24
362480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define	_NLOCALS	(_NROTATE - _NINPUTS - _NOUTPUT)
363480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
364480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#ifndef SZ
365480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define SZ	4	// this must be set to sizeof(RC4_INT)
366480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#endif
367480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
368480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#if SZ == 1
369480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define LKEY			ld1
370480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define SKEY			st1
371480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define KEYADDR(dst, i)	add dst = i, KTable
372480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#elif SZ == 2
373480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define LKEY			ld2
374480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define SKEY			st2
375480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define KEYADDR(dst, i)	shladd dst = i, 1, KTable
376480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#elif SZ == 4
377480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define LKEY			ld4
378480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define SKEY			st4
379480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define KEYADDR(dst, i)	shladd dst = i, 2, KTable
380480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#else
381480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define LKEY			ld8
382480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define SKEY			st8
383480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define KEYADDR(dst, i)	shladd dst = i, 3, KTable
384480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#endif
385480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
386480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#if defined(_HPUX_SOURCE) && !defined(_LP64)
387480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define ADDP	addp4
388480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#else
389480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define ADDP	add
390480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#endif
391480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
392480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org/* Define a macro for the bit number of the n-th byte: */
393480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
394480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#if defined(_HPUX_SOURCE) || defined(B_ENDIAN)
395480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define HOST_IS_BIG_ENDIAN
396480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define BYTE_POS(n)	(56 - (8 * (n)))
397480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#else
398480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# define BYTE_POS(n)	(8 * (n))
399480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#endif
400480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
401480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org/*
402480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org   We must perform the first phase of the pipeline explicitly since
403480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org   we will always load from the stable the first time. The br.cexit
404480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org   will never be taken since regardless of the number of bytes because
405480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org   the epilogue count is 4.
406480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org*/
407480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org/* MODSCHED_RC4 macro was split to _PROLOGUE and _LOOP, because HP-UX
408480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org   assembler failed on original macro with syntax error. <appro> */
409480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define MODSCHED_RC4_PROLOGUE						   \\
410480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{								   \\
411480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				ld1		Data[0] = [InPtr], 1;	   \\
412480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				add		IFinal = 1, I[1];	   \\
413480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				KEYADDR(IPr[0], I[1]);			   \\
414480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;								   \\
415480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{								   \\
416480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				LKEY		SI[0] = [IPr[0]];	   \\
417480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				mov		pr.rot = 0x10000;	   \\
418480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				mov		ar.ec = 4;		   \\
419480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;								   \\
420480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{								   \\
421480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				add		J = J, SI[0];		   \\
422480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				zxt1		I[0] = IFinal;		   \\
423480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				br.cexit.spnt.few .+16; /* never taken */  \\
424480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
425480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#define MODSCHED_RC4_LOOP(label)					   \\
426480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orglabel:									   \\
427480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{	.mmi;							   \\
428480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeI)	ld1		Data[0] = [InPtr], 1;	   \\
429480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeI)	add		IFinal = 1, I[1];	   \\
430480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeJ)	zxt1		J = J;			   \\
431480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}{	.mmi;							   \\
432480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pOutput)	LKEY		T[1] = [T[1]];		   \\
433480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeT)	add		T[0] = SI[2], SJ[1];	   \\
434480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeI)	KEYADDR(IPr[0], I[1]);			   \\
435480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;								   \\
436480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{	.mmi;							   \\
437480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeT)	SKEY		[IPr[2]] = SJ[1];	   \\
438480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeT)	SKEY		[JP[1]] = SI[2];	   \\
439480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeT)	zxt1		T[0] = T[0];		   \\
440480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}{	.mmi;							   \\
441480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeI)	LKEY		SI[0] = [IPr[0]];	   \\
442480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeJ)	KEYADDR(JP[0], J);			   \\
443480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeI)	cmp.eq.unc	pBypass, p0 = I[1], J;	   \\
444480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;								   \\
445480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{	.mmi;							   \\
446480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeJ)	LKEY		SJ[0] = [JP[0]];	   \\
447480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pOutput)	xor		Data[3] = Data[3], T[1];   \\
448480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				nop		0x0;			   \\
449480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}{	.mmi;							   \\
450480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeT)	KEYADDR(T[0], T[0]);			   \\
451480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pBypass)	mov		SI[0] = SI[1];		   \\
452480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeI)	zxt1		I[0] = IFinal;		   \\
453480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;								   \\
454480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{	.mmb;							   \\
455480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pOutput)	st1		[OutPtr] = Data[3], 1;	   \\
456480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		(pComputeI)	add		J = J, SI[0];		   \\
457480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org				br.ctop.sptk.few label;			   \\
458480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
459480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
460480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	.text
461480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
462480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	.align	32
463480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
464480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	.type	RC4, \@function
465480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	.global	RC4
466480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
467480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	.proc	RC4
468480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	.prologue
469480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
470480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgRC4:
471480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
472480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	  	.mmi
473480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		alloc	r2 = ar.pfs, _NINPUTS, _NLOCALS, _NOUTPUT, _NROTATE
474480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
475480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.rotr Data[4], I[2], IPr[3], SI[3], JP[2], SJ[2], T[2], \\
476480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		      OutWord[2]
477480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.rotp pPhase[4]
478480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
479480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		InPrefetch = 0, InputBuffer
480480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		KTable = 0, StateTable
481480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
482480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
483480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
484480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		InPtr = 0, InputBuffer
485480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		OutPtr = 0, OutputBuffer
486480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		mov		RetVal = r0
487480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
488480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	;;
489480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
490480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
491480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.nt1	[InPrefetch], 0x80
492480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		OutPrefetch = 0, OutputBuffer
493480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
494480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{               // Return 0 if the input length is nonsensical
495480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org        	.mib
496480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		StateTable = 0, StateTable
497480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org        	cmp.ge.unc  	L_NOK, L_OK = r0, DataLen
498480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	(L_NOK) br.ret.sptk.few rp
499480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
500480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	;;
501480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
502480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org        	.mib
503480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org        	cmp.eq.or  	L_NOK, L_OK = r0, InPtr
504480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org        	cmp.eq.or  	L_NOK, L_OK = r0, OutPtr
505480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
506480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
507480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
508480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mib
509480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org        	cmp.eq.or  	L_NOK, L_OK = r0, StateTable
510480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
511480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	(L_NOK) br.ret.sptk.few rp
512480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
513480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	;;
514480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		LKEY		I[1] = [KTable], SZ
515480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org/* Prefetch the state-table. It contains 256 elements of size SZ */
516480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
517480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#if SZ == 1
518480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		tmp0 = 1*128, StateTable
519480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#elif SZ == 2
520480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		tmp0 = 3*128, StateTable
521480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		tmp1 = 2*128, StateTable
522480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#elif SZ == 4
523480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		tmp0 = 7*128, StateTable
524480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		tmp1 = 6*128, StateTable
525480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#elif SZ == 8
526480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		tmp0 = 15*128, StateTable
527480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		tmp1 = 14*128, StateTable
528480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#endif
529480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		;;
530480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#if SZ >= 8
531480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp0], -256	// 15
532480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp1], -256;;
533480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp0], -256	// 13
534480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp1], -256;;
535480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp0], -256	// 11
536480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp1], -256;;
537480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp0], -256	//  9
538480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp1], -256;;
539480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#endif
540480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#if SZ >= 4
541480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp0], -256	//  7
542480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp1], -256;;
543480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp0], -256	//  5
544480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp1], -256;;
545480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#endif
546480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#if SZ >= 2
547480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp0], -256	//  3
548480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp1], -256;;
549480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org#endif
550480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
551480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mii
552480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.fault.nt1		[tmp0]		//  1
553480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		add		I[1]=1,I[1];;
554480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		zxt1		I[1]=I[1]
555480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
556480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
557480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
558480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.nt1	[InPrefetch], 0x80
559480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.excl.nt1	[OutPrefetch], 0x80
560480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.save		pr, PRSave
561480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		mov		PRSave = pr
562480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
563480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
564480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
565480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.excl.nt1	[OutPrefetch], 0x80
566480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		LKEY		J = [KTable], SZ
567480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		EndPtr = DataLen, InPtr
568480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}  ;;
569480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
570480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
571480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		ADDP		EndPtr = -1, EndPtr	// Make it point to
572480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org							// last data byte.
573480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		mov		One = 1
574480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.save		ar.lc, LCSave
575480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		mov		LCSave = ar.lc
576480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.body
577480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
578480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
579480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmb
580480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		sub		Remainder = 0, OutPtr
581480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		cmp.gtu		pSmall, p0 = $threshold, DataLen
582480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org(pSmall)	br.cond.dpnt	.rc4Remainder		// Data too small for
583480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org							// big loop.
584480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
585480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
586480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
587480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		and		Remainder = 0x7, Remainder
588480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		;;
589480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		cmp.eq		pAligned, pUnaligned = Remainder, r0
590480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
591480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
592480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
593480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmb
594480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.pred.rel	"mutex",pUnaligned,pAligned
595480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org(pUnaligned)	add		Remainder = -1, Remainder
596480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org(pAligned)	sub		Remainder = EndPtr, InPtr
597480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org(pAligned)	br.cond.dptk.many .rc4Aligned
598480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
599480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
600480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
601480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
602480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
603480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		mov.i		ar.lc = Remainder
604480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
605480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
606480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org/* Do the initial few bytes via the compact, modulo-scheduled loop
607480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org   until the output pointer is 8-byte-aligned.  */
608480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
609480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		MODSCHED_RC4_PROLOGUE
610480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		MODSCHED_RC4_LOOP(.RC4AlignLoop)
611480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
612480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
613480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mib
614480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		sub		Remainder = EndPtr, InPtr
615480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		zxt1		IFinal = IFinal
616480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		clrrrb				// Clear CFM.rrb.pr so
617480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		;;				// next "mov pr.rot = N"
618480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org						// does the right thing.
619480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
620480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
621480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
622480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		mov		I[1] = IFinal
623480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
624480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
625480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
626480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
627480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
628480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.rc4Aligned:
629480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
630480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org/*
631480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org   Unrolled loop count = (Remainder - ($unroll_count+1)*$phases)/($unroll_count*$phases)
632480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org */
633480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
634480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
635480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mlx
636480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		add	LoopCount = 1 - ($unroll_count + 1)*$phases, Remainder
637480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		movl		Remainder = 0xaaaaaaaaaaaaaaab
638480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
639480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
640480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
641480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		setf.sig	f6 = LoopCount		// M2, M3	6 cyc
642480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		setf.sig	f7 = Remainder		// M2, M3	6 cyc
643480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
644480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
645480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
646480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mfb
647480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
648480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		xmpy.hu		f6 = f6, f7
649480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
650480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
651480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
652480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
653480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		getf.sig	LoopCount = f6;;	// M2		5 cyc
654480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
655480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		shr.u		LoopCount = LoopCount, 4
656480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
657480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
658480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
659480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
660480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
661480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		mov.i		ar.lc = LoopCount
662480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
663480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
664480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org/* Now comes the unrolled loop: */
665480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
666480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.rc4Prologue:
667480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___
668480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
669480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$iteration = 0;
670480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
671480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# Generate the prologue:
672480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$predicates = 1;
673480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgfor ($i = 0; $i < $phases; ++$i) {
674480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &emit_body (\$code, \$bypass, $iteration++, $predicates);
675480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $predicates = ($predicates << 1) | 1;
676480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
677480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
678480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$code.=<<___;
679480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.rc4Loop:
680480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___
681480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
682480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# Generate the body:
683480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgfor ($i = 0; $i < $unroll_count*$phases; ++$i) {
684480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &emit_body (\$code, \$bypass, $iteration++, $predicates);
685480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
686480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
687480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$code.=<<___;
688480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.rc4Epilogue:
689480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___
690480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
691480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# Generate the epilogue:
692480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgfor ($i = 0; $i < $phases; ++$i) {
693480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    $predicates <<= 1;
694480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org    &emit_body (\$code, \$bypass, $iteration++, $predicates);
695480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org}
696480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
697480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$code.=<<___;
698480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
699480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
700480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		lfetch.nt1	[EndPtr]	// fetch line with last byte
701480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		mov		IFinal = I[1]
702480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
703480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
704480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
705480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.rc4Remainder:
706480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
707480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
708480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		sub		Remainder = EndPtr, InPtr	// Calculate
709480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org								// # of bytes
710480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org								// left - 1
711480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
712480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		nop		0x0
713480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
714480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
715480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mib
716480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		cmp.eq		pDone, p0 = -1, Remainder // done already?
717480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		mov.i		ar.lc = Remainder
718480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org(pDone)		br.cond.dptk.few .rc4Complete
719480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	}
720480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
721480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org/* Do the remaining bytes via the compact, modulo-scheduled loop */
722480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
723480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		MODSCHED_RC4_PROLOGUE
724480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		MODSCHED_RC4_LOOP(.RC4RestLoop)
725480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
726480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org.rc4Complete:
727480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
728480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mmi
729480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		add		KTable = -SZ, KTable
730480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		add		IFinal = -1, IFinal
731480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		mov		ar.lc = LCSave
732480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
733480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
734480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mii
735480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		SKEY		[KTable] = J,-SZ
736480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		zxt1		IFinal = IFinal
737480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		mov		pr = PRSave, 0x1FFFF
738480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
739480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	{
740480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		.mib
741480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		SKEY		[KTable] = IFinal
742480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		add		RetVal = 1, r0
743480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org		br.ret.sptk.few	rp
744480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	} ;;
745480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___
746480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
747480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org# Last but not least, emit the code for the bypass-code of the unrolled loop:
748480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
749480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$code.=$bypass;
750480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
751480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org$code.=<<___;
752480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org	.endp RC4
753480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org___
754480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.org
755480da75abf485e7e2a6be5acc0f71842368792c0jnd@chromium.orgprint $code;
756