ノスタルジックな
スプライト機能とmruby
@mgwsuzuki
2018/4/11 @mgwsuzuki 1
Arty Z7にスプライト表示機能を実装した
• Arty Z7
• Arm Cortex-A9を内蔵したFPGAを搭載
• HDMI出力ができる
• 秋月電子で購入可能(2万円台)
2018/4/11 @mgwsuzuki 2
FPGA
• デジタル回路をプログラミングできるLSI
• verilogやVHDLといったハードウェア記述言語(HDL)で設計
• スピードや回路規模を無視すればCPUやGPUを作ることも可能
• Arty Z7搭載のFPGAはXilinx社から無償の開発ツールをダウンロードして開発できる
2018/4/11 @mgwsuzuki 3
スプライト
• 80年代ゲーム機(ex:スーパーファミコン)で使われた画像表示技術
• ドット絵のキャラクタ
• ノスタルジックな技術
位置:x0, y0
キャラ: id0
位置:x2, y2
キャラ: id2
スプライトごとに位置とキャラクタ指
定したら後はハードウェアが自動的
に画像を作ってくれる
2018/4/11 @mgwsuzuki 4
実装した回路のスペック
本回路 スーパーファミコン X68000
解像度 1024x768 256x224(?) 256x256~1024x768(16色)
スプライト表示可能色数 32768 32768から16色x8パレット 65536から16色x16パレット
最大スプライト数 1024 128 128
最大横表示スプライト数 80(min) 32 32
スプライトサイズ 16x16 8x8,16x16,32x32,64x64 16x16
※スプライト機能に絞ったスペックを調べたつもりだけど、よくわからんです
2018/4/11 @mgwsuzuki 5
ラインバッファ方式による画像生成
• 何か書こうと思ったけどマニアックなので割愛
• 画面の横方向1ラインごとに表示画像をレンダリングするイメージ
• KByte単位のメモリ量で頑張ってリッチな画像表現を!!
• なにせ1980年代の技術なので…
• GPUのメモリはGB単位、クロック周波数もGHz単位の昨今、こんな技
術にこだわるのは酔狂
2018/4/11 @mgwsuzuki 6
実機動作
• 1024個のスプライトの同時表示
2018/4/11 @mgwsuzuki 7
1024個のスプライトが飛び回る
• Cによる実装
• 1スプライトあたり8byteのデータを書き換えればよい
• でも、Cじゃ面倒くさくない?
• インタプリタ的なものが欲しい
• スプライト機能はオブジェクト指向と相性いいのでは?(知らんけど)
• mrubyを組み込んでみよう!!
2018/4/11 @mgwsuzuki 8
mruby
• mruby-1.4
• ホストはwindows
• クロスコンパイル先はZynq 7000シリーズのOS無し
• arm-none-eabi
• ツールチェインはXilinx社のXSDKを拝借
• mruby本体だけではなく、compilerとインタラクティブUIであるmirbも
組み込んだ
2018/4/11 @mgwsuzuki 9
mrubyとハードウェアのインターフェイス
• SpriteElem, Sprite, Sprite::updateはmrbgemで記述
class SpriteElem
attr_accessor :y, :x, :c_id, :op
attr_reader :s_id
def initialize(sprite_id)
@s_id = sprite_id
@y = -16 #表示位置x
@x = 0 #表示位置y
@c_id = 0 #表示キャラ指定
@op = 0
end
end
class Sprite
attr_accessor :sobj
def initialize(size) #size: 使いたいスプライト数
@sobj = Array.new(size)
size.times {|n|
@sobj[n] = SpriteElem.new(n)
}
end
end
#使い方
$sp = Sprite.new(64) #同時に64個のスプライトを使う
$sp.sobj[0].x = 100 #スプライト0の座標指定
$sp.sobj[0].y = 120
$sp.update #ハードウェアへ書き込み
2018/4/11 @mgwsuzuki 10
スプライトに動きをつける
• 1秒に60回、画面を書き終えるたびにCPUへ割り込みが入る
• ユーザはcv_isr(sw)というメソッドを定義することで割りこみのたびにスプライトの
位置を更新する
• 引数swはボード上のスイッチの状態を示しており、これに応じてスプライトの動き
を変化させることもできる
#mrubyにあらかじめ定義する
def cv_isr_base(sw)
if respond_to?(:cv_isr) #cv_isrメソッドが定義されていたら
return cv_isr(sw) #コールする
else
return nil
end
end
// Cからmrubyのcv_isr_baseというメソッドをコールする
mrb_funcall(mrb, mrb_top_self(mrb), "cv_isr_base", 1,mrb_fixnum_value(sw_btn));
# スプライトの位置を更新する
def cv_isr(sw)
$sp.sobj[0].x += 1
$sp.sobj[0].y = 100
$sp.update
end
2018/4/11 @mgwsuzuki 11

Hardwre Sprite controled by mruby