0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

任天堂GBAで字体及び文字列を表示する仕組み

0
Posted at

目的

任天堂GBAで文字表示をする仕組みを整えます。
初めは字体すらないので自分で作っていきますが、いきなりASCIIを全て作るのは大変過ぎるので、大文字英字26文字と数字を作ります。一部の文字が不格好ですがそのうち直します。

実機検証

904c19bbab97a8

ビルド

リンカスクリプト及び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}, //

};
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?