// Concurrency test, program B of a pair (see gnoConcurA.c).  B announces its
// flag, spins waiting for A's, then does real work.  Both markers set means the
// two SEPARATE programs genuinely time-sliced under GNO's preemptive scheduler.
//
//   0x025042  0001  flagB: B is alive
//   0x025046  BBBB  B saw A's flag (rendezvous) AND sumTo(100)==5050; else DEAD
#include <stdint.h>

#define M(a)   (*(volatile uint16_t *)(a))
#define FLAG_A 0x025040UL
#define FLAG_B 0x025042UL
#define RES_B  0x025046UL
#define LIMIT  100000000UL


static uint16_t sumTo(uint16_t n) {
    uint16_t acc;
    uint16_t i;
    acc = 0;
    for (i = 1; i <= n; i++) {
        acc = acc + i;
    }
    return acc;
}


int main(void) {
    unsigned long spin;
    uint16_t      saw;

    M(RES_B)  = 0xDEAD;
    M(FLAG_B) = 0x0001;                  // announce B

    saw = 0;
    for (spin = 0; spin < LIMIT; spin++) {
        if (M(FLAG_A) == 0x0001) {
            saw = 1;
            break;
        }
    }

    if (saw == 1 && sumTo(100) == 5050) {
        M(RES_B) = 0xBBBB;               // rendezvous + real work OK
    }
    M(0x02504AUL) = 0xE0BB;              // B reached end (distinguishes timeout from crash)
    for (volatile unsigned long j = 0; j < 300000UL; j++) {
    }
    return 0;
}
