[C,ASM] check CARRY flag from C

55 posts / 0 new
Last post
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all : )

I'm looking how to read CARRY flag from SREG after certain operation - LEFT SHIFT.

Sample code is following:

char carry;
char data;

data = data<<1;
// There I need to read bit that was shifted out into carry

It is clear to me this is job for inline ASM, but I never work with ASM in C.

Can you give me some advice?

David

David Sedláček

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do not even dream of accessing the Carry flag in C. It is not guaranteed to be valid in C.

If you want to know whether a carry is shifted out, you simply:

char data;
// just check bit 7 before the shift.
char carry = (data & 0x80) != 0;
data = data<<1;

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

David's reply covers the vast majority of possible uses, but if you believe you need better and you tell us why do you think you need the carry bit, we might come up with alternative solutions.

Jan

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Generally, I'm trying to write MFM coder as simple as it is possible. Input is byte array, output is MFM-coded stream.

If it helps you, there is whole procedure - I'm not saying that is the best solution, but until now i haven't wrote better solution.

Base idea, if I understood it OK, is that data bits (x,y,z,...) are coded to (x,x NOR y, y NOR z, z, z NOR .......)

So I came with this solution. David, your code will work of course, but I think variant with use of CARRY flag will save some instructions.

void FDDIO_encodeMfm() {
    char carry = 0;
    char prvek = FDD_sector[0];
    prvek = (prvek << 1);
    //!!! carry = ?; !!!
    // Data x
    FDD_sectorMfm[0] |= carry;
    
    for(int i = 0; i < 658;i++) {
        prvek = FDD_sector[i];
        for(c = 0; c < 9; c++) {
            // CLOCK  x NOR y
            FDD_sectorMfm[i] = (short) (FDD_sectorMfm[i] << 1);
            FDD_sectorMfm[i] |= carry;
                if(c==8 && i!= (658-1)) prvek = FDD_sector[i+1];
            prvek = (prvek<<1);
            //!!! carry = ?; !!!
            FDD_sectorMfm[i] |= carry;
            FDD_sectorMfm[i] ^= (1<<0); 
            
            // DATA y
            if(c < 8) {
                FDD_sectorMfm[i] = (FDD_sectorMfm[i] << 1);
                FDD_sectorMfm[i] |= carry;	// bit 14 16bit slova, 15. je pro ulozeni clocku ktery uz souvisi s dalsim prvkem
            }
        }
    }
}

David Sedláček

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Forgotten global defs:
short FDD_sectorMfm[658];
char FDD_sector[512];

.. I have tested almost the same code on PC (java) and it works OK..

David Sedláček

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You never assign carry apart from initialising to zero.

I should just write the algorithm to be accurate. Do not worry about the efficiency.

Once you are working, by all means optimise it.

I notice that you have multiple array references. Some compilers may spot this. OTOH, you might just as well introduce a temporary variable.

Note that you can equally well use a 16-bit int. Then the 'carry' is in bit 8.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
            prvek = (prvek<<1); 
            carry = SREG & (1<<7) != 0; 

This could give you the current state of the carry bit, but you must realize what "current" means. It is certainly not the state of the carry bit immediately after the shift since, at the very least, the asignment to prvek has happened since then. There could also be several opcodes run in preparation of reading SREG that might have changed its value. And worst case, an interrupt might have occurred in between which means hundreds or even thousands of opcodes could have been run.

Davids solution of using a 16 bit int sounds easiest to me (however, you need to change the declaration of prvek to unsigned char, which is probably advisable anyways):

unsigned int temp = prvek << 1;;
prvek = temp;
carry = temp >> 8;

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
And worst case, an interrupt might have occurred in between which means hundreds or even thousands of opcodes could have been run.
If you use a compiler that does not preserve SREG in interrupts, then you should consider to use a different one. ;-)

(of course the central point "reading Carry from SREG in C is pointless" is true nevertheless)

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, you can read SREG as any other IO register, but this will not bring you any closer with your

Quote:
I'm trying to write MFM coder as simple as it is possible (..)with GCC

idea because GCC does not understand SREG flags and their brbx functionality.

No RSTDISBL, no fun!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey guys I dont want to work with 16bit integer unless it is not efficient. There must be way to do it in inline ASM this is what I'm asking for : ).
I'm not saying it must be only SREG bit saving line, but what if whole left shift and then SREG bit save section, or more, will be in inline ASM?

Koshchi it is as you wrote - there is some operation(s) after LSHIFT and it is not guaranteed that in CARRY will be correct val.

Again, see this in pseudocode and compare efficiency:

prvek <<= 1;
prvekMfm |= (SREG&1);

... which I need to convert into inline ASM or generic way:

carry = (prvek >>7);
prvek <<= 1;
prvekMfm |= carry;

:?: 8)

David Sedláček

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you actually looked at what code the compiler generates for an implementation in C? Do that, and then tell what needs further optimization.

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington]

Pages