9. フレームバッファでグラフィックス - その1

下の図は Linux Zaurus で 今回のサンプルプログラムを実行した結果です。 フレームバッファに関する情報を取得した後、画面左下の部分に32ドットx32ドットの 赤い正方形を描画しています。フレームバッファはプログラムからメモリとして アクセスすることができます。フレームバッファの領域のメモリに対して 読み書きすることで画面に自由に描画することができます。SL Zaurus の画面は Qtライブラリを使って描画されていますが、ここでは Qtライブラリを無視して フレームバッファを直接操作しています。

B500 C700 QVGA
240 x 320 240 x 320
B500 C700QVGA
C700 VGA
640 x 480
C700

フレームバッファの構造

axis

スクリーンショット中の赤い正方形は 座標 (32, 0)から 32ドットx32ドットの大きさで描画しています。B500、C700ともに画面左下に表示されていることから X座標は左下から上に向かって増加し、Y座標は左から右に向かって増加します。 フレームバッファのメモリの内容は、メモリアドレスが増加する順に左の図の赤い矢印のように表示されます。 1ピクセルは2バイトになっているため、Xを1増加するためにはメモリアドレスを「+2」、 Yを1増加するためにはX方向の1行分のバイト数を加える必要があります。

SL Zaurusのフレームバッファは左下から左上に X が増加し、左から右へ Y が増加する 構造になっています。PCのフレームバッファを左に90度回転させた形になっていることがわかります。

赤 5 ビット緑 6 ビット青 5 ビットを使ってピクセルあたり 2 バイトで 65536 色の表示が可能です。

次の表は今回のサンプルプログラムで表示されるフレームバッファの情報をまとめたものです。 調べていませんが、C750 と C760 も C700 と同じではないかと思います。 数多くの値がありますが、機種やモードで変化する重要なものを赤で示してあります。 結局、X と Y の解像度、X の1行の長さ だけを使えば機種とモードの違いに対応できます。(カーネルのバージョンアップで例えば色数などが可変になれば状況はかわりますが)

機種 B500 C700QVGA C700VGA C700VGA縦
Frame Buffer Physical Screen Information
ID string cotulla_fb W100FB W100FB W100FB
frame buffer mem start 0xA0300000 0x08800000 0x08800000 0x08800000
frame buffer mem length 153600 393216 2097152 2097152
frame buffer type 0 0 0 0
interleave 0 0 0 0
frame buffer visual 2 2 2 2
x pan step 0 0 0 0
y pan step 0 0 0 0
y wrap step 0 0 0 0
line length (bytes) 640 640 960 960
Memory Mapped I/O start 0x00000000 0x08010000 0x08010000 0x08010000
Memory Mapped I/O length 0 8192 8192 8192
acceleration type 0 0 0 0
Frame Buffer Virtual Screen Information
x resolution 320 320 480 480
y resolution 240 240 640 640
x res virtual 320 320 480 480
y res virtual 240 240 640 640
x offset 0 0 0 0
y offset 0 0 0 0
bits/pixel 16 16 16 16
grayscale 0 0 0 0
RED offset 11 11 11 11
RED length 5 5 5 5
RED msb_right 0 0 0 0
GREEN offset 5 5 5 5
GREEN length 6 6 6 6
GREEN msb_right 0 0 0 0
BLUE offset 0 0 0 0
BLUE length 5 5 5 5
BLUE msb_right 0 0 0 0
TRANSP offset 0 0 0 0
TRANSP length 0 0 0 0
TRANSP msb_right 0 0 0 0
nonstd 0 0 0 0
activate 0 0 0 0
height 240 -1 -1 -1
width 320 -1 -1 -1
accel_flags 0 0 0 0
pixclock 0 4 4 4
left margin 0 0 0 0
right margin 0 0 0 0
upper margin 0 0 0 0
lower margin 0 0 0 0
hsync length 0 0 0 0
vsync length 0 0 0 0
sync 0 0 0 0
vmode 0 0 0 0

フレームバッファは以下のようにして使います。

ファイルをランダムアクセスするために「ファイルをメモリにマップしてメモリを操作する」 方法と同じです。

フレームバッファ用ライブラリ

フレームバッファを使う上で必要となる決まった操作をサブルーチンとして用意しておきます。 フレームバッファのオープン, クローズ、設定の変更と復帰などです。

@-------------------------------------------------------------------------
@  file : fblib.s
@  2003/10/05
@  Copyright (C) 2003  Jun Mizutani <[email protected]>
@-------------------------------------------------------------------------

.ifndef __FBLIB
__FBLIB = 1



.ifndef __SYSCALL
.include    "syscalls.s"
.endif

.ifndef O_RDWR
O_RDWR                  = 2
.endif

PROT_READ               = 0x1     @ page can be read
PROT_WRITE              = 0x2     @ page can be written
MAP_SHARED              = 0x01    @ Share changes

FBIOGET_VSCREENINFO     = 0x4600
FBIOPUT_VSCREENINFO     = 0x4601
FBIOGET_FSCREENINFO     = 0x4602
FBIOGETCMAP             = 0x4604
FBIOPUTCMAP             = 0x4605

@==============================================================

.text

@-------------------------------------------------------------------------
@ open framebuffer device file
@-------------------------------------------------------------------------
fbdev_open:
        stmfd   sp!, {r1-r2, lr}
        adr     r0, fb_device           @ open /dev/fb0
        mov     r1, #O_RDWR             @ flag
        mov     r2, #0                  @ mode
        swi     #sys_open
        ldr     r1, fb_desc
        str     r0, [r1]                @ save fd
        ldr     r1, mmap_arg
        str     r0, [r1, #+16]          @ fd
        cmp     r0, #0
        ldmfd   sp!, {r1-r2, pc}        @ return
fb_device:
        .asciz  "/dev/fb0"

        .align  2
@-------------------------------------------------------------------------
@ close framebuffer
@-------------------------------------------------------------------------
fbdev_close:
        stmfd   sp!, {r0, r1, lr}
        ldr     r1, fb_desc             @ close /dev/fb0
        ldr     r0, [r1]
        swi     #sys_close
        tst     r0, r0
        ldmfd   sp!, {r0, r1, pc}       @ return

@-------------------------------------------------------------------------
@ フレームバッファの物理状態を取得
@-------------------------------------------------------------------------
fb_get_fscreen:
        stmfd   sp!, {r0-r2, lr}
        ldr     r1, fb_desc
        ldr     r0, [r1]
        ldr     r1, =FBIOGET_FSCREENINFO
        ldr     r2, fscinfo             @ 保存先指定
        swi     #sys_ioctl
        cmp     r0, #0
        ldmfd   sp!, {r0-r2, pc}        @ return

@-------------------------------------------------------------------------
@ 現在のフレームバッファの状態を取得
@-------------------------------------------------------------------------
fb_get_screen:
        stmfd   sp!, {r0-r2, lr}
        ldr     r1, fb_desc
        ldr     r0, [r1]
        ldr     r1, =FBIOGET_VSCREENINFO
        ldr     r2, scinfsave           @ 保存先指定
        swi     #sys_ioctl
        cmp     r0, #0
        ldmfd   sp!, {r0-r2, pc}        @ return

@-------------------------------------------------------------------------
@ フレームバッファ設定を書きこむ
@-------------------------------------------------------------------------
fb_set_screen:
        stmfd   sp!, {r0-r2, lr}
        ldr     r1, fb_desc
        ldr     r0, [r1]
        ldr     r1, =FBIOPUT_VSCREENINFO
        ldr     r2, scinfdata           @ 設定済みデータ
        swi     #sys_ioctl
        cmp     r0, #0
        ldmfd   sp!, {r0-r2, pc}        @ return

@-------------------------------------------------------------------------
@ 保存済みのフレームバッファ設定を新規設定用にコピー
@-------------------------------------------------------------------------
fb_copy_scinfo:
        stmfd   sp!, {r0-r3, lr}
        ldr     r0, scinfsave
        ldr     r1, scinfdata
        ldr     r2, fb_screeninfo_size
   1:   ldr     r3, [r0],#4             @ post-indexed addressing
        str     r3, [r1],#4
        subs    r2, r2, #1
        bne     1b
        ldmfd   sp!, {r0-r3, pc}        @ return

@-------------------------------------------------------------------------
@ フレームバッファメモリをマッピング
@-------------------------------------------------------------------------
fb_map_screen:
        stmfd   sp!, {r1-r2, lr}
        ldr     r0, scinfsave           @ screen_info structure
        ldr     r1, [r0, #+12]          @ yres_virtual
        ldr     r2, [r0, #+8]           @ xres_virtual
        mul     r1, r2, r1              @ x * y
        ldr     r2, [r0, #+24]          @ bits_per_pixel
        mov     r2, r2, LSR #3
        mul     r1, r2, r1              @ r1 = x*y*depth/8

        ldr     r0, mmap_arg
        str     r1, [r0, #+4]           @ mmap_arg_len
        ldr     r2, =(PROT_READ|PROT_WRITE)
        str     r2, [r0, #+8]           @ mmap_arg_prot
        ldr     r2, =MAP_SHARED
        str     r2, [r0, #+12]          @ mmap_arg_flags
        mov     r1, #0
        str     r1, [r0]                @ mmap_arg_addr
        str     r1, [r0, #+20]          @ mmap_arg_offset
        swi     #old_mmap               @ 90
        ldr     r1, fb_addr
        str     r0, [r1]
        cmp     r0, #0
        ldmfd   sp!, {r1-r2, pc}        @ return

@-------------------------------------------------------------------------
@ フレームバッファメモリをアンマップ
@-------------------------------------------------------------------------
fb_unmap_screen:
        stmfd   sp!, {r0-r2, lr}
        adr     r2, mmap_arg
        ldr     r0, [r2]                @ adr
        ldr     r1, [r2, #+4]           @ len
        swi     #sys_munmap
        tst     r0, r0
        ldmfd   sp!, {r0-r2, pc}        @ return

@-------------------------------------------------------------------------
@ 保存済みのフレームバッファ設定を復帰
@-------------------------------------------------------------------------
fb_restore_sc:
        stmfd   sp!, {r0-r2, lr}
        adr     r1, fb_desc
        ldr     r0, [r1]
        ldr     r1, =FBIOPUT_VSCREENINFO
        ldr     r2, scinfsave
        swi     #sys_ioctl
        tst     r0, r0
        ldmfd   sp!, {r0-r2, pc}        @ return


@==============================================================

                    .align   2

mmap_arg:               .long   _mmap_arg
scinfsave:              .long   scinfo_save
scinfdata:              .long   scinfo_data
fscinfo:                .long   fsc_info
fb_screeninfo_size:     .long   (scinfo_data - scinfo_save)/4
fb_desc:                .long   _fb_desc
fb_addr:                .long   _fb_addr

.pool

@==============================================================
.bss

_fb_desc:               .long   0
_fb_addr:               .long   0

_mmap_arg:
mmap_arg_addr:          .long   0   @ mmap_arg[0]
mmap_arg_len:           .long   0   @ mmap_arg[4]
mmap_arg_prot:          .long   0   @ mmap_arg[8]
mmap_arg_flags:         .long   0   @ mmap_arg[12]
mmap_arg_fd:            .long   0   @ mmap_arg[16]
mmap_arg_offset:        .long   0   @ mmap_arg[20]

scinfo_save:
sis_xres:               .long   0   @ visible resolution
sis_yres:               .long   0
sis_xres_virtual:       .long   0   @ virtual resolution
sis_yres_virtual:       .long   0
sis_xoffset:            .long   0   @ offset from virtual to visible
sis_yoffset:            .long   0   @ resolution
sis_bits_per_pixel:     .long   0   @ guess what
sis_grayscale:          .long   0   @ != 0 Graylevels instead of colors
sis_red_offset:         .long   0   @ beginning of bitfield
sis_red_length:         .long   0   @ length of bitfield
sis_red_msb_right:      .long   0   @ != 0 : Most significant bit is
sis_green_offset:       .long   0   @ beginning of bitfield
sis_green_length:       .long   0   @ length of bitfield
sis_green_msb_right:    .long   0   @ != 0 : Most significant bit is
sis_blue_offset:        .long   0   @ beginning of bitfield
sis_blue_length:        .long   0   @ length of bitfield
sis_blue_msb_right:     .long   0   @ != 0 : Most significant bit is
sis_transp_offset:      .long   0   @ beginning of bitfield
sis_transp_length:      .long   0   @ length of bitfield
sis_transp_msb_right:   .long   0   @ != 0 : Most significant bit is
sis_nonstd:             .long   0   @ != 0 Non standard pixel format
sis_activate:           .long   0   @ see FB_ACTIVATE_*
sis_height:             .long   0   @ height of picture in mm
sis_width:              .long   0   @ width of picture in mm
sis_accel_flags:        .long   0   @ acceleration flags (hints)
sis_pixclock:           .long   0   @ pixel clock in ps (pico seconds)
sis_left_margin:        .long   0   @ time from sync to picture
sis_right_margin:       .long   0   @ time from picture to sync
sis_upper_margin:       .long   0   @ time from sync to picture
sis_lower_margin:       .long   0
sis_hsync_len:          .long   0   @ length of horizontal sync
sis_vsync_len:          .long   0   @ length of vertical sync
sis_sync:               .long   0   @ see FB_SYNC_*
sis_vmode:              .long   0   @ see FB_VMODE_*
sis_reserved:           .space  24  @ Reserved for future compatibility

scinfo_data:            .skip   (scinfo_data - scinfo_save)

fsc_info:
fsi_id:                 .space  16  @  0 identification string
fsi_smem_start:         .long   0   @ 16 Start of frame buffer mem
fsi_smem_len:           .long   0   @ 20 Length of frame buffer mem
fsi_type:               .long   0   @ 24 see FB_TYPE_*
fsi_type_aux:           .long   0   @ 28 Interleave for interleaved Planes
fsi_visual:             .long   0   @ 32 see FB_VISUAL_*
fsi_xpanstep:           .hword  0   @ 36 zero if no hardware panning
fsi_ypanstep:           .hword  0   @ 38 zero if no hardware panning
fsi_ywrapstep:          .hword  0   @ 40 zero if no hardware ywrap
fsi_padding:            .hword  0   @ 42 for alignment, jm 1/26/2001
fsi_line_length:        .long   0   @ 44 length of a line in bytes
fsi_mmio_start:         .long   0   @ 48 Start of Memory Mapped I/O
fsi_mmio_len:           .long   0   @ 52 Length of Memory Mapped I/O
fsi_accel:              .long   0   @ 56 Type of acceleration available
fsi_reserved:           .space  6   @ Reserved for future compatibility

.endif

各サブルーチンを簡単に解説します。レジスタは変化しません。

fbdev_open
フレームバッファのデバイスファイルをオープン。最初に呼びます。
fbdev_close
フレームバッファのデバイスファイルをクローズ。最後に呼びます。
fb_get_fscreen
フレームバッファの物理状態を fscinfo に取得します。
fb_get_screen
現在のフレームバッファの状態を scinfo_save に取得します。たとえば sis_xres でX方向の解像度を知ることができます。これで取得した値を 使うことで異なる画面モードに対応した描画が可能になります。
fb_copy_scinfo
保存済みのフレームバッファ設定scinfo_save を新規設定用に scinfo_data にコピー。 設定を変更する場合にコピーに変更を加え、オリジナルは復帰用に残しておきます。 SL Zaurusでは使う必要はないかもしれません。
fb_set_screen
フレームバッファ設定 scinfo_data を書き込みます。 グラフィックのチップにネイティブに対応したフレームバッファの場合は 動的に変更することができます。
fb_map_screen
フレームバッファをメモリをマッピングします。 マッピングされたメモリの先頭アドレスが r0 に返ります。fb_addr にも同じ値が設定されます。このアドレスから始まるメモリに値を書き込むと 画面に表示されるようになります。
fb_unmap_screen
フレームバッファメモリをアンマップ。フレームバッファが不要になったら呼びます。

サンプル

上で用意したライブラリと前回のプログラムを利用したフレームバッファを使ったサンプルプログラムです。 物理的な画面情報と論理的な画面情報、メモリにマップされたフレームバッファの先頭アドレスとサイズを表示した後、赤い正方形を描画します。 fb_get_fscreen と fb_get_screen で得られた情報にアクセスする場合の参考にして下さい。 フレームバッファの情報の意味を表示するための文字列が多いため長くなってしまいました。赤い正方形を描画する部分は 15行だけ です。

@-------------------------------------------------------------------------
@  file : fbinfo.s
@  2003/10/05
@  Copyright (C) 2003  Jun Mizutani <[email protected]>
@-------------------------------------------------------------------------

.include    "syscalls.s"
.include    "fblib.s"
.include    "stdio.s"

.text
.align  2
.global _start

@-------------------------------------------------------------------------
@  メイン
@-------------------------------------------------------------------------
_start:
        @-------------------------------------------
        @ フレームバッファの準備
        @-------------------------------------------
        bl      fbdev_open          @ /dev/fb0 をオープン
        bmi     fb_Error
        bl      fb_get_fscreen      @ 物理スクリーン情報を取得
        bl      fb_get_screen       @ スクリーン情報を取得
        bmi     fb_Error
        bl      fb_copy_scinfo      @ scinfo_data を設定
        bl      fb_map_screen       @ メモリにマッピング
        bmi     fb_Error

        @-------------------------------------------
        @ フレームバッファの情報を表示
        @-------------------------------------------
        adr     r3, fbinfo_msg00
        ldr     r0, [r3], #4
        bl      OutAsciiZ           @ Physical Screen Information title
        bl      NewLine
        ldr     r0, [r3], #4
        bl      OutAsciiZ           @ id string
        ldr     r2, fsc_info0
        mov     r0, r2
        add     r2, r2, #16
        bl      OutAsciiZ
        bl      NewLine
        bl      print_hex_data      @ frame buffer mem start
        mov     r1, #4
        bl      print_long_data

        mov     r1, #3
    1:  ldr     r0, [r3], #4
        bl      OutAsciiZ
        ldrh    r0, [r2], #2        @ hword
        bl      PrintLeft
        bl      NewLine
        subs    r1, r1, #1
        bne     1b
        add     r2, r2, #2          @ skip padding

        mov     r1, #1
        bl      print_long_data
        bl      print_hex_data      @ Memory Mapped I/O start
        mov     r1, #2
        bl      print_long_data

        ldr     r0, [r3],#4
        bl      OutAsciiZ           @ Virtual Screen Information
        ldr     r2, scinfo_data0
        mov     r1, #34
        bl      print_long_data

        @-------------------------------------------
        @ フレームバッファのアドレス
        @-------------------------------------------
        ldr     r0, maped_addr0
        bl      OutAsciiZ
        ldr     r1, fb_addr
        ldr     r0, [r1]            @ 先頭アドレス
        bl      PrintHex8
        bl      NewLine
        ldr     r0, maped_length0
        bl      OutAsciiZ
        ldr     r1, mmap_arg
        ldr     r0, [r1, #4]        @ サイズ
        bl      PrintLeft
        bl      NewLine

        @-------------------------------------------
        @ フレームバッファに描画
        @-------------------------------------------
        ldr     r1, fb_addr
        ldr     r0, [r1]            @ 先頭アドレス
        add     r0, r0, #64         @ 32ドット上
        ldr     r1, fsc_info0
        ldr     r1, [r1, #44]       @ 1行のバイト数
        sub     r1, r1, #64         @ 次行までのオフセット
        mov     r3, #32
    2:  mov     r2, #32
        mov     ip, #0xF800         @ 赤
    3:  strh    ip, [r0], #2
        subs    r2, r2, #1
        bne     3b
        add     r0, r0, r1
        subs    r3, r3, #1
        bne     2b

        @-------------------------------------------
        @ フレームバッファの後始末
        @-------------------------------------------
        bl      fb_restore_sc       @ 保存済みの設定を復帰
        bl      fb_unmap_screen
        bl      fbdev_close
    fb_Error:
        b       Exit

@-------------------------------------------------------------------------
@  情報表示用サブルーチン
@-------------------------------------------------------------------------
print_long_data:
        stmfd   sp!, {lr}
    1:  ldr     r0, [r3], #4
        bl      OutAsciiZ
        ldr     r0, [r2], #4
        bl      PrintLeft
        bl      NewLine
        subs    r1, r1, #1
        bne     1b
        ldmfd   sp!, {pc}

print_hex_data:
        stmfd   sp!, {lr}
        ldr     r0, [r3], #4
        bl      OutAsciiZ
        ldr     r0, [r2], #4
        bl      PrintHex8
        bl      NewLine
        ldmfd   sp!, {pc}

@-------------------------------------------------------------------------
@ .data, .bss セクションのアドレス
@-------------------------------------------------------------------------
fsc_info0:      .long   fsc_info            @ fblib.s
scinfo_data0:   .long   scinfo_data         @ fblib.s
fbinfo_msg00:   .long   fbinfomsg00         @ 表示用メッセージ格納アドレス
fbinfo_msg01:   .long   fbinfomsg01
fbinfo_msg02:   .long   fbinfomsg02
fbinfo_msg03:   .long   fbinfomsg03
fbinfo_msg04:   .long   fbinfomsg04
fbinfo_msg05:   .long   fbinfomsg05
fbinfo_msg06:   .long   fbinfomsg06
fbinfo_msg07:   .long   fbinfomsg07
fbinfo_msg08:   .long   fbinfomsg08
fbinfo_msg09:   .long   fbinfomsg09
fbinfo_msg10:   .long   fbinfomsg10
fbinfo_msg11:   .long   fbinfomsg11
fbinfo_msg12:   .long   fbinfomsg12
fbinfo_msg13:   .long   fbinfomsg13
fbinfo_msg20:   .long   fbinfomsg20
fbinfo_msg21:   .long   fbinfomsg21
fbinfo_msg22:   .long   fbinfomsg22
fbinfo_msg23:   .long   fbinfomsg23
fbinfo_msg24:   .long   fbinfomsg24
fbinfo_msg25:   .long   fbinfomsg25
fbinfo_msg26:   .long   fbinfomsg26
fbinfo_msg27:   .long   fbinfomsg27
fbinfo_msg28:   .long   fbinfomsg28
fbinfo_msg29:   .long   fbinfomsg29
fbinfo_msg30:   .long   fbinfomsg30
fbinfo_msg31:   .long   fbinfomsg31
fbinfo_msg32:   .long   fbinfomsg32
fbinfo_msg33:   .long   fbinfomsg33
fbinfo_msg34:   .long   fbinfomsg34
fbinfo_msg35:   .long   fbinfomsg35
fbinfo_msg36:   .long   fbinfomsg36
fbinfo_msg37:   .long   fbinfomsg37
fbinfo_msg38:   .long   fbinfomsg38
fbinfo_msg39:   .long   fbinfomsg39
fbinfo_msg40:   .long   fbinfomsg40
fbinfo_msg41:   .long   fbinfomsg41
fbinfo_msg42:   .long   fbinfomsg42
fbinfo_msg43:   .long   fbinfomsg43
fbinfo_msg44:   .long   fbinfomsg44
fbinfo_msg45:   .long   fbinfomsg45
fbinfo_msg46:   .long   fbinfomsg46
fbinfo_msg47:   .long   fbinfomsg47
fbinfo_msg48:   .long   fbinfomsg48
fbinfo_msg49:   .long   fbinfomsg49
fbinfo_msg50:   .long   fbinfomsg50
fbinfo_msg51:   .long   fbinfomsg51
fbinfo_msg52:   .long   fbinfomsg52
fbinfo_msg53:   .long   fbinfomsg53
fbinfo_msg54:   .long   fbinfomsg54
maped_addr0:    .long   maped_addr
maped_length0:  .long   maped_length

@-------------------------------------------------------------------------
@ 文字列データ
@-------------------------------------------------------------------------
.data
                .align  2
fbinfomsg00:    .asciz  "Frame Buffer Physical Screen Information\n"
fbinfomsg01:    .asciz  " ID string               : "
fbinfomsg02:    .asciz  " frame buffer mem start  : 0x"
fbinfomsg03:    .asciz  " frame buffer mem length : "
fbinfomsg04:    .asciz  " frame buffer type       : "
fbinfomsg05:    .asciz  " interleave              : "
fbinfomsg06:    .asciz  " frame buffer visual     : "
fbinfomsg07:    .asciz  " x pan step              : "
fbinfomsg08:    .asciz  " y pan step              : "
fbinfomsg09:    .asciz  " y wrap step             : "
fbinfomsg10:    .asciz  " line length (bytes)     : "
fbinfomsg11:    .asciz  " Memory Mapped I/O start : 0x"
fbinfomsg12:    .asciz  " Memory Mapped I/O length: "
fbinfomsg13:    .asciz  " acceleration type       : "
fbinfomsg20:    .asciz  "\nFrame Buffer Virtual Screen Information\n"
fbinfomsg21:    .asciz  " x resolution      : "
fbinfomsg22:    .asciz  " y resolution      : "
fbinfomsg23:    .asciz  " x res virtual     : "
fbinfomsg24:    .asciz  " y res virtual     : "
fbinfomsg25:    .asciz  " x offset          : "
fbinfomsg26:    .asciz  " y offset          : "
fbinfomsg27:    .asciz  " bits/pixel        : "
fbinfomsg28:    .asciz  " grayscale         : "
fbinfomsg29:    .asciz  " RED    offset     : "
fbinfomsg30:    .asciz  "        length     : "
fbinfomsg31:    .asciz  "        msb_right  : "
fbinfomsg32:    .asciz  " GREEN  offset     : "
fbinfomsg33:    .asciz  "        length     : "
fbinfomsg34:    .asciz  "        msb_right  : "
fbinfomsg35:    .asciz  " BLUE   offset     : "
fbinfomsg36:    .asciz  "        length     : "
fbinfomsg37:    .asciz  "        msb_right  : "
fbinfomsg38:    .asciz  " TRANSP offset     : "
fbinfomsg39:    .asciz  "        length     : "
fbinfomsg40:    .asciz  "        msb_right  : "
fbinfomsg41:    .asciz  " nonstd            : "
fbinfomsg42:    .asciz  " activate          : "
fbinfomsg43:    .asciz  " height            : "
fbinfomsg44:    .asciz  " width             : "
fbinfomsg45:    .asciz  " accel_flags       : "
fbinfomsg46:    .asciz  " pixclock          : "
fbinfomsg47:    .asciz  " left margin       : "
fbinfomsg48:    .asciz  " right margin      : "
fbinfomsg49:    .asciz  " upper margin      : "
fbinfomsg50:    .asciz  " lower margin      : "
fbinfomsg51:    .asciz  " hsync length      : "
fbinfomsg52:    .asciz  " vsync length      : "
fbinfomsg53:    .asciz  " sync              : "
fbinfomsg54:    .asciz  " vmode             : "
maped_addr:     .asciz  " Frame buffer is mapped from 0x"
maped_length:   .asciz  " Length of Frame buffer : "
                .align  2

文字列のデータを .data セクションに置いて、各文字列の先頭アドレスを .text セクションに ポインタ配列のような形式に用意しています。文字列の先頭アドレスを r3 レジスタを使って 順次アクセスしています。

サンプルプログラムを実際にアセンブルして実行してみます。 アセンブルとリンクにはasld スクリプトを使っています。以下の例は SL-B500 で実行した結果です。

~/Documents/testarm$ asld fbinfo
~/Documents/testarm$ ./fbinfo
Frame Buffer Physical Screen Information

 ID string               : cotulla_fb
 frame buffer mem start  : 0xA0300000
 frame buffer mem length : 153600
 frame buffer type       : 0
 interleave              : 0
 frame buffer visual     : 2
 x pan step              : 0
 y pan step              : 0
 y wrap step             : 0
 line length (bytes)     : 640
 Memory Mapped I/O start : 0x00000000
 Memory Mapped I/O length: 0
 acceleration type       : 0

Frame Buffer Virtual Screen Information
 x resolution      : 320
 y resolution      : 240
 x res virtual     : 320
 y res virtual     : 240
 x offset          : 0
 y offset          : 0
 bits/pixel        : 16
 grayscale         : 0
 RED    offset     : 11
        length     : 5
        msb_right  : 0
 GREEN  offset     : 5
        length     : 6
        msb_right  : 0
 BLUE   offset     : 0
        length     : 5
        msb_right  : 0
 TRANSP offset     : 0
        length     : 0
        msb_right  : 0
 nonstd            : 0
 activate          : 0
 height            : 240
 width             : 320
 accel_flags       : 0
 pixclock          : 0
 left margin       : 0
 right margin      : 0
 upper margin      : 0
 lower margin      : 0
 hsync length      : 0
 vsync length      : 0
 sync              : 0
 vmode             : 0
 Frame buffer is mapped from 0x40000000
 Length of Frame buffer : 153600

ターミナルからフレームバッファを直接操作するプログラムを実行して 画面が上書きされて、表示がおかしくなってもホームキーを押した後、ターミナルに戻れば 画面は元に戻ります。 タスクバーが消えるような最悪の場合でもホームキーを押して設定画面に移動して、 「画面デザイン設定」からテーマを再設定するだけです。

グラフィックライブラリに頼らずに自力でグラフィックを描くのも楽しいものです。 コンピュータの世界では「車輪の再発明」といって、すでに存在するプログラム (今回はグラフィックライブラリ)を自分で作ることをバカにする意見もありますが、 「車輪の発明」の過程をたどって見ることも必要です。数学の試験は「車輪の再発明」 ばかりですよね。