From dseal@armltd.co.uk (David Seal) Fri Jan 21 09:15:39 1994
Path: doc.ic.ac.uk!warwick!zaphod.crihan.fr!univ-lyon1.fr!swidir.switch.ch!scsing.switch.ch!xlink.net!howland.reston.ans.net!pipex!uknet!armltd!dseal
From: dseal@armltd.co.uk (David Seal)
Newsgroups: comp.sys.acorn.tech
Subject: Tricks with the C flag (was Re: Constant Loading)
Message-ID: <31460@armltd.uucp>
Date: 20 Jan 94 10:55:27 GMT
References: <CJru9n.xt@brunel.ac.uk>
Sender: news@armltd.uucp
Distribution: comp
Organization: A.R.M. Ltd, Swaffham Bulbeck, Cambs, UK
Lines: 74

In article <CJru9n.xt@brunel.ac.uk> cs92dty@brunel.ac.uk (Danny T Yates)
writes:

>Clive Jones (clive@nsict.org) wrote:
>: No doubt, in particular circumstances, other weird tricks would help.
>: For example, &C9025001 could be generated by:
>:   MOVS Rn,#&C9000000
>
>Why does this set the carry flag? We haven't carried over from 32bits,
>or did I miss something?
>
>:   ADC Rn,Rn,#&25000

Immediate constants are generated by taking a simple 8-bit constant, then
rotating it right by an even amount, using the same barrel shifter as is
used for the other shift and rotate options. This even extends to the
setting of the flags.

So the above is effectively treated as though it were:

  MOVS Rn,#&C9,ROR #8

Because this is the S form of a logical operation, the N and Z flags are set
according to the value of the final result (i.e. N=1, Z=0), the V flag is
unchanged and the C flag is set to the carry output of the shifter. For an
ROR, the carry output of the shifter is equal to the last bit rotated from
the right hand end of the number to its left hand end. So in this case, C is
set to 1.

The assembler will always generate the constant without a rotation if it
can. The net result is that MOVS Rn,#X will leave C unchanged if 0 <= X <=
255 (since the carry out from the shifter is equal to the current C value
when no shift is being done) and will set C to the top bit of X otherwise.

You may occasionally want to set C in this way when 0 <= X <= 255. As long
as X can also be generated with a real rotation, this can be done by
explicitly telling the assembler how to generate X. For instance, MOVS Rn,#1
will leave C unchanged. But 1 can also be generated as a legitimate
immediate constant in other ways, namely as 4 rotated right by 2, 16 rotated
right by 4 or 64 rotated right by 6. You can explicitly tell the assembler
to generate it in these ways, by using MOVS Rn,#4,2, MOVS Rn,#16,4 or MOVS
Rn,#64,6. Any of these will set Rn to 1 and clear C as a side effect.

One other tricky piece of code using the C flag that I've used is:

  EORS  Rd,Ra,Rb,LSR #32
  ADC   Rd,Rd,Rc

What this does is the operation Rd := Rc + Ra * SIGN(Rb), where the SIGN
function is 1 when its operand is zero or positive, and -1 when its operand
is negative. (It's effectively using the standard "invert and add 1"
approach to negating a number.) A particular special case is when Rb=Ra -
i.e.:

  EORS  Rd,Ra,Ra,LSR #32
  ADC   Rd,Rd,Rc

which does Rd := Rc + ABS(Ra).

Often, you can get a free test of the sign of Rb beforehand (i.e. by using
the S option on a previous instruction), in which case this code is no
better than the more obvious:

  ADDPL Rd,Rc,Ra
  SUBMI Rd,Rc,Ra

after the free test has been done. But quite often you cannot get a free
test (e.g. if Rb has just been loaded), and in that case the tricky sequence
is better.

David Seal
dseal@armltd.co.uk

All opinions are mine only...

