Implement ATTR_CHR

This commit is contained in:
Lior Halphon 2020-03-13 13:35:54 +02:00
parent e7f6ac8828
commit 84e8e45b7b

View File

@ -17,6 +17,7 @@ enum {
ATTR_BLK = 0x04, ATTR_BLK = 0x04,
ATTR_LIN = 0x05, ATTR_LIN = 0x05,
ATTR_DIV = 0x06, ATTR_DIV = 0x06,
ATTR_CHR = 0x07,
PAL_SET = 0x0A, PAL_SET = 0x0A,
PAL_TRN = 0x0B, PAL_TRN = 0x0B,
DATA_SND = 0x0F, DATA_SND = 0x0F,
@ -254,6 +255,52 @@ static void command_ready(GB_gameboy_t *gb)
} }
break; break;
} }
case ATTR_CHR: {
struct __attribute__((packed)) {
uint8_t x, y;
uint16_t length;
uint8_t direction;
uint8_t data[];
} *command = (void *)(gb->sgb->command + 1);
uint16_t count = command->length;
#ifdef GB_BIG_ENDIAN
count = __builtin_bswap16(count);
#endif
uint8_t x = command->x;
uint8_t y = command->y;
if (x >= 20 || y >= 18 || (count + 3) / 4 > sizeof(gb->sgb->command) - sizeof(*command) - 1) {
/* TODO: Verify with the SFC BIOS */
break;
}
for (unsigned i = 0; i < count; i++) {
uint8_t palette = (command->data[i / 4] >> (((~i) & 3) << 1)) & 3;
gb->sgb->attribute_map[x + 20 * y] = palette;
if (command->direction) {
y++;
if (y == 18) {
x++;
y = 0;
if (x == 20) {
x = 0;
}
}
}
else {
x++;
if (x == 20) {
y++;
x = 0;
if (y == 18) {
y = 0;
}
}
}
}
break;
}
case ATTR_LIN: { case ATTR_LIN: {
struct { struct {
uint8_t count; uint8_t count;