strcpy
Chris Torek
chris at mimsy.UUCP
Sun Apr 3 06:52:33 AEST 1988
>In article <10895 at mimsy.UUCP> I mentioned that
>>... The 4.3BSD Vax strcpy() uses the Vax locc and movc3 instructions.
In article <848 at cresswell.quintus.UUCP> ok at quintus.UUCP (Richard
A. O'Keefe) writes:
>This may not be such a wonderful idea: according to the DEC manuals,
>some VAX models do not implement the locc instruction. (The machine
>will trap to some sort of library which emulates the missing instructions.)
This is true. In particular, the Microvax I and II chips do not.
(Indeed, the uVax I does not even implement movc3 in hardware.) The II
traps to kernel code that emulates locc. (And people wonder why
strcpy() and index() are slow there! I argued for a `getcputype'
syscall just for library optimisation, but no one has done it.)
>Getting this right for strings longer than 2^16-a few characters must be
>a nightmare: both locc and movc3 have a 16-bit length operand. (This
>has never made sense to me.)
(Since VMS string descriptor lengths are Words rather than Longwords,
obviously no one would ever want strings longer than that. Right.)
Actually, it is not that bad; in particular, movc3 leaves registers
r1 and r3 pointing to the `next' string, so that you wind up with
something like this:
# strcpy(dst, src)
...
loop:
/* src in r1, dst in r3 */
locc $0,$65535,src # find the \0 in src
beql last_block # if we found it, finish up
movc3 $65535,src,dst # otherwise move 64K
brb loop # and keep going
last_block:
/* convert to a count and move <65535 bytes */
The code for bcopy/memcpy/memmove that handles overlapping `backwards'
moves, however, is perhaps best described as `amusing':
/* length in r6, src in r1, dst in r3 */
addl2 r6,r1 # jump to end of block
addl2 r6,r3
movzwl $65535,r0 # get a handy 64K
brb 5f
4:
subl2 r0,r6 # count 64K moved
/* here begins the silliness: note how r1 and r3 need adjustment now */
subl2 r0,r1 # ... from 64K behind where we were
subl2 r0,r3
movc3 r0,(r1),(r3) # the VAX does this back to front
movzwl $65535,r0 # but we still have to fix the pointers
/* ... and again! */
subl2 r0,r1 # afterward
subl2 r0,r3
5:
cmpl r6,r0 # 64K?
bgtr 4b # more
subl2 r6,r1 # 64K or less;
subl2 r6,r3 # adjust the pointers
movc3 r6,(r1),(r3) # and move
movl 4(ap),r0 # always return dst
ret
In other words, even though the microcode decides to move the string
`back to front' (high addresses to low addresses), and therefore sets
the registers to count down from the top, it very carefully adjusts
them afterward so that they point to the high addresses---exactly what
we do NOT want. (I suspect the high bits of one of the counting
registers are used to flag the direction, which would give another
reason why the lengths are limited. Too bad they are not limited
to 30 bits, which is as much as you can address in one segment [no,
not iNTEL segments].)
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain: chris at mimsy.umd.edu Path: uunet!mimsy!chris
More information about the Comp.lang.c
mailing list