我正在try 使用GBA平铺模式显示一个带有单色像素的平铺,从头开始.
它主要起作用,但不是设置单个像素,而是在16位对齐的位置将相同的 colored颜色 设置为两个字节,我打算在其中写入:
运行mgba emulator时生成的图像:
The emulator allows to inspect the tiles, memory and register.
Tilesmap, showing the two pixels set on the tiles.
VRAM, starting at the tiles address, showing that there are indeed two 8bpp pixel set, referencing the color in palette at index 42.
Display Control Register nothing unexpected, running in first tile mode with background 0 enabled.
Background 0 Control register, in 8bpp mode.
主要内容:
#include "screen.h"
void do_it() {
// [tile_index][row][column] = palette index
VRAM.tilesets[3].d_tiles[37][0][0] = 42;
}
int main() {
// [tilemap][row][column] = tile_index
VRAM.tilemaps[0][0][0] = 37;
do_it();
PALETTE.backgrounds[42] = rgb(0b1111, 0b11111, 0);
BG0CNT = BGCNT_SIZE_32X32 | BGCNT_COLOR_8BPP | (0 << BGCNT_TILEMAP_INDEX) | (3 << BGCNT_TILESET_INDEX);
DISPCNT = DISPCNT_MODE_TILE_0 | DISPCNT_BACKGROUND_0;
while (1) {};
}
屏幕的有用部分.h:
typedef unsigned char tile_4bpp[8][4];
typedef unsigned char tile_8bpp[8][8];
typedef union {
tile_4bpp s_tiles[512];
tile_8bpp d_tiles[256];
} char_block;
extern union {
char_block tilesets[4];
screen_block tilemaps[32];
color bitmap[HEIGHT][WIDTH];
} VRAM;
So in the function do_it
, I am setting a single byte value, only once at an hardcoded location.
Yet in memory, it set the value to the given address AND the one that complete 2 bytes alignment:
VRAM.tilesets[3].d_tiles[37][0][0] = 42;
and VRAM.tilesets[3].d_tiles[37][0][1] = 42;
have the same outcome.
我原以为我可以在 struct /联合/类型定义中做得很糟糕,但汇编看起来不错:
Disassembly of section .text:
080000e8 <do_it>:
80000e8: 4b02 ldr r3, [pc, #8] ; (80000f4 <do_it+0xc>)
80000ea: 4a03 ldr r2, [pc, #12] ; (80000f8 <do_it+0x10>)
80000ec: 212a movs r1, #42 ; 0x2a
80000ee: 5499 strb r1, [r3, r2]
80000f0: 46c0 nop ; (mov r8, r8)
80000f2: 4770 bx lr
80000f4: 06000000 streq r0, [r0], -r0
80000f8: 0000c940 andeq ip, r0, r0, asr #18
080000fc <main>:
80000fc: b510 push {r4, lr}
80000fe: 4b09 ldr r3, [pc, #36] ; (8000124 <main+0x28>)
8000100: 2225 movs r2, #37 ; 0x25
8000102: 801a strh r2, [r3, #0]
8000104: f7ff fff0 bl 80000e8 <do_it>
8000108: 4b07 ldr r3, [pc, #28] ; (8000128 <main+0x2c>)
800010a: 2254 movs r2, #84 ; 0x54
800010c: 4907 ldr r1, [pc, #28] ; (800012c <main+0x30>)
800010e: 5299 strh r1, [r3, r2]
8000110: 4b07 ldr r3, [pc, #28] ; (8000130 <main+0x34>)
8000112: 228c movs r2, #140 ; 0x8c
8000114: 801a strh r2, [r3, #0]
8000116: 4b07 ldr r3, [pc, #28] ; (8000134 <main+0x38>)
8000118: 2280 movs r2, #128 ; 0x80
800011a: 0052 lsls r2, r2, #1
800011c: 801a strh r2, [r3, #0]
800011e: 46c0 nop ; (mov r8, r8)
8000120: e7fd b.n 800011e <main+0x22>
8000122: 46c0 nop ; (mov r8, r8)
8000124: 06000000 streq r0, [r0], -r0
8000128: 05000000 streq r0, [r0, #-0]
800012c: 000003ef andeq r0, r0, pc, ror #7
8000130: 04000008 streq r0, [r0], #-8
8000134: 04000000 streq r0, [r0], #-0
我不擅长手臂装配,但do_it
中的strb
似乎与矫揉造作相匹配,它应该根据arm doc操作一个字节.
更多信息:
- 它发生在多个模拟器上:我通常使用mgba,它也发生在vbam上
- mgba上预期的其他ROM工作
- 使用arm none eabi gcc工具链v 12.1.0构建
- 没有任何优化标志
- 使用
-mthumb -mthumb-interwork -mcpu=arm7tdmi -fomit-frame-pointer -ffast-math -fno-strict-aliasing
- 4bpp模式也会发生这种情况,设置四个像素,而不是预期的两个像素
- 代码直接从gamepak1内存运行
- 当使用不同的TILESET/tilemaps位置时会发生这种情况
- 在位图模式下运行时发生:
这可以工作并在屏幕左上角显示一个绿色像素:
int main() {
VRAM.bitmap[0][0] = rgb(0b1111, 0b11111, 0);
DISPCNT = DISPCNT_MODE_3 | DISPCNT_BACKGROUND_2;
while (1) {};
}
可在此处找到完整的代码库:github
你知道这是什么原因吗?