Rabbit processor bug

I think I found a bug in the implementation of ALTD DJNZ instruction. According to Rabbit instructions manual, the ASLD DJNZ should act on alternate register B’ and decrement it. The observed behavior is that B’ is set to 0xFF and not decremented.

The following program illustrates this issue:


// function returns 5
int take_5 ()
{
#asm
  ld hl, 0
  ld  b, 5
.loop:
  inc  hl
  djnz .loop
#endasm
}

// this is the buggy version
int alt_take_5 ()
{
#asm
  ld hl, 0
  altd ld  b, 5
.loop:
  inc  hl
  altd djnz .loop
#endasm
}

void main ()
{
  int val;
  brdInit();

  val = take_5 ();
  printf ("take 5 = %d
", val);
  val = alt_take_5 ();
  printf ("alt take 5 = %d
", val);
  exit (0);
}

The bug shows on Rabbit 2000, 3000 and 4000 processors. I haven’t tried on newer ones.

I think it’s possible to describe this as expected behavior.

DJNZ loads from B, decrements the value and then stores back to B before deciding whether to jump.

By specifying ALTD, you’re loading from B, decrementing, and then storing to B’. Since B is 0x00, you’re always loading B’ with 0xFF.

In this case, you’d somehow need a combination of ALTS and ALTD, but I don’t believe that’s a supported operation. I tried manually embedding both opcodes before the DJNZ opcode, but it didn’t work correctly. I think that’s because ALTS and ALTD only apply to the next opcode, not the “next opcode that isn’t an ALTx”. Or the use of ALTD overrides the conditions set by using ALTS.

Thanks Tom! In the meantime I figured that one out. I hope you’ll agree with me that it makes ALTD DJNZ quite useless :slight_smile: