0

I'm writing an ARM11 emulator and now I'm trying to set CPRS flags which are N(negative result), Z(zero), C(carry out) and V(overflow)

this is what the spec says:

The C bit in logical operations (and, eor, orr, teq, tst and mov) will be set to the carry out from any shift operation (i.e.the result from the barrel shifter). In arithmetic operations (add, sub, rsb and cmp) the C bit will be set to the carry out of the bit 31 of the ALU.

My question is, how do I determine the carry out from logical and arithmetic operations? Operations work on two uint32_t, e.g. my eor operation simply returns x ^ y, and after that I need to set CPRS flags.

EDIT: For addition, C is set to 1 if the addition produced a carry (unsigned over ow), it is set to 0 otherwise. For subtraction (including comparison), the bit C is set to 0 if the subtraction produced a borrow, otherwise is set to 1.

Jongware
  • 22,200
  • 8
  • 54
  • 100
akalikin
  • 1,071
  • 12
  • 35
  • 1
    Example: to determine if a carry out occurred with `unsigned` addition of `c = a + b;`, `Carryout = c < a;` – chux - Reinstate Monica Jun 04 '14 at 17:36
  • @chux sorry, should have mentioned, spec says that overflow bit is left unchanged, but when it occuurs after addition - then you just set carry out bit. What I really don't know how to do is the rest. – akalikin Jun 04 '14 at 17:38

2 Answers2

1

Logical operations are a bit of a red herring here - obviously eor r0, r1, r2 isn't going to produce overflow or carry. However, it's not the logical operations themselves that we care about:

The C bit in logical operations (and, eor, orr, teq, tst and mov) will be set to the carry out from any shift operation (i.e.the result from the barrel shifter).

Remember that optional shift on any data processing instruction? Given eor r0, r1, r2 lsl #3, the carry you care about is whatever r2 lsl #3 generates. However you're implementing flag-setting for shifts*, do that.

* if you're stuck on that too, I saw plenty of good ideas in a quick flick through the related questions over there -->

Notlikethat
  • 20,095
  • 3
  • 40
  • 77
0

I posit that the code snippet below is probably as close as you're going to get with standard C and using logic operations to determine carry out and signed arithmetic overflow. This approach is an adaptation of how look ahead carry circuits are generated for arbitrary word lengths in FPGA's.

The basic sequence is to first determine which bit pairs will generate a carry and which will propagate a carry. In this presentation, the initial carry-in is presumed to be zero. A mask is marched along the "generate" and "propagate" words and with some logic and previous carry, determine carry to the next iteration. At the end of iteration, the carry flag will be set (or not) depending on the word pair bits to be added. The downside, is that this programming loop would be repeated every time you wanted to determine carry out and overflow for a given word pair - no such penalty in physical circuits or FPGA.

As a bonus, it's super easy to determine an overflow flag, which indicates whether the 2's compliment addition will be representable from the summation.
See the reference links below.

The code is for 32-bit integers, however could be adapted for longer or shorter types.

http://www.righto.com/2012/12/the-6502-overflow-flag-explained.html

https://en.wikipedia.org/wiki/Carry-lookahead_adder

// Global carry and overflow flags
// Set by carryLookahead()
bool carry, ov;


// Determines presence of carry out and overflow from 2's compliment addition
//
bool carryLookahead(int32 f1, int32 f2){
unsigned long mask;
unsigned long g,p;
unsigned char i;
// uses & sets global carry and ov flag variables

    mask=1;
    carry=ov=false; // initial carry and overflow flag assumed to be zero

    g = f1 & f2;  // bit pairs that will generate carry
    p = f1 | f2;  // bit pairs that will propagate a carry

    for(i=0; i < 32; ++i, mask <<= 1){
        ov=carry; // set ov to last carry
        carry = (g&mask) || (p&mask) && carry;  // use logical rather than bitwise logic to set the current carry;
        ov=ov^carry; // ov is xor of last and current carries
    }

    return(carry);

}