目的
任天堂GBAで文字表示をする仕組みを整えます。
初めは字体すらないので自分で作っていきますが、いきなりASCIIを全て作るのは大変過ぎるので、大文字英字26文字と数字を作ります。一部の文字が不格好ですがそのうち直します。
実機検証
ビルド
リンカスクリプト及びROMのヘッダファイルは以下の記事のものを使用します。
ビルドの手順は筆者の以下の記事を参考
GBA自作コードを実機で動作させる手順
arm-none-eabi-as header.s -o header.o
arm-none-eabi-gcc -c main.c -o main.o -nostdlib -ffreestanding
arm-none-eabi-gcc -c font.c -o font.o -nostdlib -ffreestanding
arm-none-eabi-ld header.o main.o font.o -T link.ld -o out.elf
arm-none-eabi-objcopy -O binary out.elf out.gba
コード
main.c
#include "font.h"
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#define REG_DISPCNT (*(volatile uint16_t*)0x04000000) // 画面制御レジスタ
#define VRAM ((volatile uint16_t*)0x06000000)
#define FONT_WIDTH 8
#define FONT_HEIGHT 8
#define CHAR_SPACING 1
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 160
//文字座標位置(広域変数がROM領域に置かれてしまい更新不可な為強引な暫定措置)
//作法的に汚いので修正予定。rodataの調整が必要。
volatile int *text_pos_x=(volatile int*)0x03000000;
volatile int *text_pos_y=(volatile int*)0x03000004;
static inline void putpixel(int x, int y, uint16_t c) {
if (x < 0 || x >= SCREEN_WIDTH ||
y < 0 || y >= SCREEN_HEIGHT)
return;
VRAM[y * SCREEN_WIDTH + x] = c;
}
void printfont(int x, int y, int c, uint16_t color) {
for (int row = 0; row < FONT_HEIGHT; row++) {
uint8_t bits = font[c][row];
for (int col = 0; col < FONT_WIDTH; col++) {
if (bits & (1 << (7 - col))) {
putpixel(x + col, y + row, color);
}
}
}
}
/* カーソル付き描画 */
void putchar(char c, uint16_t color) {
// 改行処理
if (c == '\n') {
*text_pos_x = 1; // 左端へ
*text_pos_y += FONT_HEIGHT + 2; // 1 行下げる
return;
}
printfont(*text_pos_x, *text_pos_y, c, color);
*text_pos_x += FONT_WIDTH + CHAR_SPACING;
/* 画面右端で折り返す */
if (*text_pos_x + FONT_WIDTH >= SCREEN_WIDTH) {
*text_pos_x = 1;
*text_pos_y += FONT_HEIGHT + 2;
}
}
void print(const char *str, uint16_t color) {
while (*str) {
putchar(*str++, color);
}
}
void println(const char *str, uint16_t color) {
print(str, color);
putchar('\n', color);
}
void main(void)
{
// Mode3 + BG2
REG_DISPCNT = 0x0403;
*text_pos_x=1;
*text_pos_y=1;
println("THE QUICK BROWN FOX", 0xFFFF);
println("JUMPS OVER THE LAZY DOG", 0xFFFF);
print("0123456789", 0xFFFF);
while (1);
};
font.h
#ifndef FONT_H
#define FONT_H
typedef unsigned char uint8_t;
extern const uint8_t font[128][8];
#endif
font.c
#include "font.h"
const uint8_t font[128][8] = {
// 0 0x30=48
['0'] =
{0b00111100, // ████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ████
0b00000000}, //
// 1 0x31=49
['1'] =
{0b00011000, // ██
0b00111000, // ███
0b00011000, // ██
0b00011000, // ██
0b00011000, // ██
0b00011000, // ██
0b00111100, // ████
0b00000000}, //
// 2 0x32=50
['2'] =
{0b00111100, // ██████
0b01100110, // ██ ██
0b00000110, // ██
0b00011100, // ██
0b00110000, // ██
0b01100000, // ██
0b01111110, // ████████
0b00000000}, //
// 3 0x33=51
['3'] =
{0b00111100, // ██████
0b01100110, // ██ ██
0b00000110, // ██
0b00011100, // ███
0b00000110, // ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// 4 0x34=52
['4'] =
{0b00001100, // ██
0b00011100, // ███
0b00111100, // ████
0b01101100, // ██ ██
0b01111110, // ████████
0b00001100, // ██
0b00001100, // ██
0b00000000}, //
// 5 0x35=53
['5'] =
{0b01111110, // ████████
0b01100000, // ██
0b01111100, // ██████
0b00000110, // ██
0b00000110, // ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// 6 0x36=54
['6'] =
{0b00011100, // ████
0b00110000, // ██
0b01100000, // ██
0b01111100, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// 7 0x37=55
['7'] =
{0b01111110, // ████████
0b00000110, // ██
0b00001100, // ██
0b00011000, // ██
0b00110000, // ██
0b00110000, // ██
0b00110000, // ██
0b00000000}, //
// 8 0x38=56
['8'] =
{0b00111100, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// 9 0x39=57
['9'] =
{0b00111100, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111110, // ██████
0b00000110, // ██
0b00001100, // ██
0b00111000, // ████
0b00000000}, //
// A 0x41=65
['A'] =
{0b00011000, // ██
0b00111100, // ████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01111110, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00000000}, //
// B 0x42=66
['B'] =
{0b01111100, // █████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01111100, // █████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01111100, // █████
0b00000000}, //
// C 0x43=67
['C'] =
{0b00111100, // ██████
0b01100110, // ██ ██
0b01100000, // ██
0b01100000, // ██
0b01100000, // ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// D 0x44=68
['D'] =
{0b01111000, // █████
0b01101100, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01101100, // ██ ██
0b01111000, // █████
0b00000000}, //
// E 0x45=69
['E'] =
{0b01111110, // ████████
0b01100000, // ██
0b01100000, // ██
0b01111100, // ██████
0b01100000, // ██
0b01100000, // ██
0b01111110, // ████████
0b00000000}, //
// F 0x46=70
['F'] =
{0b01111110, // ████████
0b01100000, // ██
0b01100000, // ██
0b01111100, // ██████
0b01100000, // ██
0b01100000, // ██
0b01100000, // ██
0b00000000}, //
// G 0x47=71
['G'] =
{0b00111100, // ██████
0b01100110, // ██ ██
0b01100000, // ██
0b01100000, // ██
0b01101110, // ██ ███
0b01100110, // ██ ██
0b00111110, // ██████
0b00000000}, //
// H 0x48=72
['H'] =
{0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01111110, // ████████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00000000}, //
// I 0x49=73
['I'] =
{0b00111100, // ██████
0b00011000, // ██
0b00011000, // ██
0b00011000, // ██
0b00011000, // ██
0b00011000, // ██
0b00111100, // ██████
0b00000000}, //
// J 0x4A=74
['J'] =
{0b00001110, // ███
0b00000110, // ██
0b00000110, // ██
0b00000110, // ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// K 0x4B=75
['K'] =
{0b01100110, // ██ ██
0b01101100, // ██ ██
0b01111000, // ████
0b01110000, // ███
0b01111000, // ████
0b01101100, // ██ ██
0b01100110, // ██ ██
0b00000000}, //
// L 0x4C=76
['L'] =
{0b01100000, // ██
0b01100000, // ██
0b01100000, // ██
0b01100000, // ██
0b01100000, // ██
0b01100000, // ██
0b01111110, // ████████
0b00000000}, //
// M 0x4D = 77
['M'] =
{0b11000110, // █ █
0b11000110, // ██ ██
0b11000110, // ██ ██
0b11101110, // ███ ███
0b11111110, // ████████
0b11000110, // ██ ██
0b11000110, // █ █
0b00000000},
// N 0x4E=78
['N'] =
{0b11000110, // ██ ██
0b11100110, // ███ ██
0b11110110, // ████ ██
0b11111110, // █████ ██
0b11011110, // ██ █████
0b11001110, // ██ ███
0b11000110, // ██ ██
0b00000000}, //
// O 0x4F=79
['O'] =
{0b00111100, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// P 0x50=80
['P'] =
{0b01111100, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01111100, // ██████
0b01100000, // ██
0b01100000, // ██
0b01100000, // ██
0b00000000}, //
// Q 0x51=81
['Q'] =
{0b00111100, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01101110, // ██ ███
0b01100110, // ██ ██
0b00111110, // ██████
0b00000000}, //
// R 0x52=82
['R'] =
{0b01111100, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01111100, // ██████
0b01101100, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00000000}, //
// S 0x53=83
['S'] =
{0b00111100, // ██████
0b01100110, // ██ ██
0b01100000, // ██
0b00111100, // ██████
0b00000110, // ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// T 0x54=84
['T'] =
{0b01111110, // ████████
0b00011000, // ██
0b00011000, // ██
0b00011000, // ██
0b00011000, // ██
0b00011000, // ██
0b00011000, // ██
0b00000000}, //
// U 0x55=85
['U'] =
{0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00000000}, //
// V 0x56=86
['V'] =
{0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00011000, // ██
0b00000000}, //
// W 0x57 = 87
['W'] =
{
0b01000010, // █ █
0b01000010, // █ █
0b01000010, // █ █
0b01100110, // ██ ██
0b01111110, // ████████
0b01100110, // ██ ██
0b01000010, // █ █
0b00000000,
},
// X 0x58=88
['X'] =
{0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00011000, // ██
0b00111100, // ██████
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00000000}, //
// Y 0x59=89
['Y'] =
{0b01100110, // ██ ██
0b01100110, // ██ ██
0b01100110, // ██ ██
0b00111100, // ██████
0b00011000, // ██
0b00011000, // ██
0b00011000, // ██
0b00000000}, //
// Z 0x5A=90
['Z'] =
{0b01111110, // ████████
0b00000110, // ██
0b00001100, // ██
0b00011000, // ██
0b00110000, // ██
0b01100000, // ██
0b01111110, // ████████
0b00000000}, //
};