/* $OpenBSD: bzero.S,v 1.1 2006/11/17 22:32:38 miod Exp $ */
/*
* Mach Operating System
* Copyright (c) 1993-1992 Carnegie Mellon University
* Copyright (c) 1991 OMRON Corporation
* Copyright (c) 1996 Nivas Madhur
* Copyright (c) 1998 Steve Murphree, Jr.
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
#include <machine/asm.h>
/*######################################################################*/
/*
* April 1990, Omron Corporation
* jfriedl@nff.ncl.omron.co.jp
*
* void bzero(destination, length)
*
* Clear (set to zero) LENGTH bytes of memory starting at DESTINATION.
* Note that there is no return value.
*
* This is fast. Really fast. Especially for long lengths.
*/
#define R_dest r2
#define R_len r3
#define R_bytes r4
#define R_mark_address r5
#define R_addr r6 /* R_addr && R_temp SHARE */
#define R_temp r6 /* R_addr && R_temp SHARE */
ENTRY(bzero)
/*
* If the destination is not word aligned, we'll word align
* it first to make things easier.
*
* We'll check to see first if bit #0 is set and then bit #1
* (of the destination address). If either are set, it's
* not word aligned.
*/
bb1 0, R_dest, _ASM_LABEL(not_initially_word_aligned)
bb1 1, R_dest, _ASM_LABEL(not_initially_word_aligned)
ASLOCAL(now_word_aligned)
/*
* before we get into the main loop, grab the
* address of the label "mark" below.
*/
or.u R_mark_address, r0, hi16(_ASM_LABEL(mark))
or R_mark_address, R_mark_address, lo16(_ASM_LABEL(mark))
ASLOCAL(top_of_main_loop)
#define MAX_AT_ONE_TIME 128
/*
* Now we find out how many words we can zero-fill in a row.
* We do this by doing something like:
*
* bytes &= 0xfffffffc;
* if (bytes > MAX_AT_ONE_TIME)
* bytes = MAX_AT_ONE_TIME;
*/
/*
* Clear lower two bits of length to give us the number of bytes
* ALIGNED TO THE WORD LENGTH remaining to move.
*/
clr R_bytes, R_len, 2<0>
/* if we're done clearing WORDS, jump out */
bcnd eq0, R_bytes, _ASM_LABEL(done_doing_words)
/* if the number of bytes > MAX_AT_ONE_TIME, do only the max */
cmp R_temp, R_bytes, MAX_AT_ONE_TIME
bb1 lt, R_temp, 1f
/*
* Since we're doing the max, we know exactly where we're
* jumping (the first one in the list!), so we can jump
* right there. However, we've still got to adjust
* the length, so we'll jump to where we ajust the length
* which just happens to fall through to the first store zero
* in the list.
*
* Note, however, that we're jumping to an instruction that
* would be in the delay slot for the jump in front of it,
* so if you change things here, WATCH OUT.
*/
br.n do_max
or R_bytes, r0, MAX_AT_ONE_TIME
1:
/*
* Now we have the number of bytes to zero during this iteration,
* (which, as it happens, is the last iteration if we're here).
* We'll calculate the proper place to jump and then jump there,
* after adjusting the length. NOTE that there is a label between
* the "jmp.n" and the "subu" below... the "subu" is NOT always
* executed in the delay slot of the "jmp.n".
*/
subu R_addr, R_mark_address, R_bytes
/* and go there (after adjusting the length via ".n") */
jmp.n R_addr
ASLOCAL(do_max)
subu R_len, R_len, R_bytes /* NOTE: this is in the delay slot! */
st r0, R_dest, 0x7c /* 128 */
st r0, R_dest, 0x78 /* 124 */
st r0, R_dest, 0x74 /* 120 */
st r0, R_dest, 0x70 /* 116 */
st r0, R_dest, 0x6c /* 112 */
st r0, R_dest, 0x68 /* 108 */
st r0, R_dest, 0x64 /* 104 */
st r0, R_dest, 0x60 /* 100 */
st r0, R_dest, 0x5c /* 96 */
st r0, R_dest, 0x58 /* 92 */
st r0, R_dest, 0x54 /* 88 */
st r0, R_dest, 0x50 /* 84 */
st r0, R_dest, 0x4c /* 80 */
st r0, R_dest, 0x48 /* 76 */
st r0, R_dest, 0x44 /* 72 */
st r0, R_dest, 0x40 /* 68 */
st r0, R_dest, 0x3c /* 64 */
st r0, R_dest, 0x38 /* 60 */
st r0, R_dest, 0x34 /* 56 */
st r0, R_dest, 0x30 /* 52 */
st r0, R_dest, 0x2c /* 44 */
st r0, R_dest, 0x28 /* 40 */
st r0, R_dest, 0x24 /* 36 */
st r0, R_dest, 0x20 /* 32 */
st r0, R_dest, 0x1c /* 28 */
st r0, R_dest, 0x18 /* 24 */
st r0, R_dest, 0x14 /* 20 */
st r0, R_dest, 0x10 /* 16 */
st r0, R_dest, 0x0c /* 12 */
st r0, R_dest, 0x08 /* 8 */
st r0, R_dest, 0x04 /* 4 */
st r0, R_dest, 0x00 /* 0 */
ASLOCAL(mark)
br.n _ASM_LABEL(top_of_main_loop)
addu R_dest, R_dest, R_bytes /* bump up the dest address */
ASLOCAL(done_doing_words)
bcnd ne0, R_len, 1f
jmp r1
1:
subu R_len, R_len, 1
bcnd.n ne0, R_len, 1b
st.b r0, R_dest, R_len
1:
jmp r1
ASLOCAL(not_initially_word_aligned)
/*
* Bzero to word-align the address (at least if the length allows it).
*/
bcnd eq0, R_len, 1b
st.b r0, R_dest, 0
addu R_dest, R_dest, 1
mask R_temp, R_dest, 0x3
bcnd.n eq0, R_temp, _ASM_LABEL(now_word_aligned)
subu R_len, R_len, 1
br _ASM_LABEL(not_initially_word_aligned)
#undef R_dest
#undef R_len
#undef R_bytes
#undef R_mark_address
#undef R_addr
#undef R_temp
#undef MAX_AT_ONE_TIME