fix random display glitches with sprite rendering

Sometimes the compiler would assign r28/29 to one of our input
variables despite our needing to use that register ourselves. This
fix attempts to prevent that from happening and also cleans up a
few other small details.

- remove unnecessary y_count (-1 register)
- set buffer_ofs_2 inside assembly (-1 register)
- require inputs/outputs to use lower or simple upper registers
This commit is contained in:
Josh Goebel 2017-08-24 21:46:29 -04:00
parent 1bb4726ed0
commit 4478b1fe0a
1 changed files with 26 additions and 22 deletions

View File

@ -245,13 +245,15 @@ void Sprites::drawBitmap(int16_t x, int16_t y,
// *2 because we use double the bits (mask + bitmap) // *2 because we use double the bits (mask + bitmap)
bofs = (uint8_t *)(bitmap + ((start_h * w) + xOffset) * 2); bofs = (uint8_t *)(bitmap + ((start_h * w) + xOffset) * 2);
uint8_t xi = rendered_width; // used for x loop below uint8_t xi = rendered_width; // counter for x loop below
uint8_t yi = loop_h; // used for y loop below
asm volatile( asm volatile(
"push r28\n" // save Y "push r28\n" // save Y
"push r29\n" "push r29\n"
"movw r28, %[buffer_page2_ofs]\n" // Y = buffer page 2 offset "movw r28, %[buffer_ofs]\n" // Y = buffer_ofs_2
"adiw r28, 63\n" // buffer_ofs_2 = buffer_ofs + 128
"adiw r28, 63\n"
"adiw r28, 2\n"
"loop_y:\n" "loop_y:\n"
"loop_x:\n" "loop_x:\n"
// load bitmap and mask data // load bitmap and mask data
@ -266,7 +268,6 @@ void Sprites::drawBitmap(int16_t x, int16_t y,
"mul %A[mask_data], %[mul_amt]\n" "mul %A[mask_data], %[mul_amt]\n"
"movw %[mask_data], r0\n" "movw %[mask_data], r0\n"
// SECOND PAGE // SECOND PAGE
// if yOffset != 0 && sRow < 7 // if yOffset != 0 && sRow < 7
"cpi %[sRow], 7\n" "cpi %[sRow], 7\n"
@ -282,7 +283,6 @@ void Sprites::drawBitmap(int16_t x, int16_t y,
"end_second_page:\n" "end_second_page:\n"
"skip_shifting:\n" "skip_shifting:\n"
// FIRST PAGE // FIRST PAGE
// if sRow >= 0 // if sRow >= 0
"tst %[sRow]\n" "tst %[sRow]\n"
@ -330,26 +330,30 @@ void Sprites::drawBitmap(int16_t x, int16_t y,
"pop r29\n" "pop r29\n"
"pop r28\n" "pop r28\n"
"clr __zero_reg__\n" // just in case "clr __zero_reg__\n" // just in case
: [xi] "+&r" (xi), : [xi] "+&a" (xi),
[yi] "+&r" (yi), [yi] "+&a" (loop_h),
[sRow] "+&d" (sRow), // CPI requires an upper register [sRow] "+&a" (sRow), // CPI requires an upper register (r16-r23)
[data] "=&r" (data), [data] "=&l" (data),
[mask_data] "=&r" (mask_data), [mask_data] "=&l" (mask_data),
[bitmap_data] "=&r" (bitmap_data) [bitmap_data] "=&l" (bitmap_data)
: :
[x_count] "r" (rendered_width), [screen_width] "M" (WIDTH),
[y_count] "r" (loop_h), [x_count] "l" (rendered_width), // lower register
[sprite_ofs] "z" (bofs), [sprite_ofs] "z" (bofs),
[buffer_ofs] "x" (Arduboy2Base::sBuffer+ofs), [buffer_ofs] "x" (Arduboy2Base::sBuffer+ofs),
[buffer_page2_ofs] "r" (Arduboy2Base::sBuffer+ofs+WIDTH), // Y pointer [buffer_ofs_jump] "a" (WIDTH-rendered_width), // lower register
[buffer_ofs_jump] "r" (WIDTH-rendered_width), [sprite_ofs_jump] "a" ((w-rendered_width)*2), // lower register
[sprite_ofs_jump] "r" ((w-rendered_width)*2),
[yOffset] "r" (yOffset), // [sprite_ofs_jump] "r" (0),
[mul_amt] "r" (mul_amt) [yOffset] "l" (yOffset), // lower register
// declaring an extra high register clobber here for some reason [mul_amt] "l" (mul_amt) // lower register
// prevents a compile error for some sketches: // NOTE: We also clobber r28 and r29 but sometimes the compiler
// can't find a register in class 'LD_REGS' while reloading 'asm' // won't allow us so in order to make this work we don't tell it
: "r24" // they we clobber them. Then we need to guarantee that the
// the compiler doesn't put one of our own variables into r28/r29.
// We do that by specifying all the inputs and outputs use either
// lower registers (l) or simple (r16-r23) upper registers (a).
: // clobbers r28 and r29
); );
break; break;
} }