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: Sender: news@armltd.uucp Distribution: comp Organization: A.R.M. Ltd, Swaffham Bulbeck, Cambs, UK Lines: 74 In article 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...