公開日:2021/10/16
title.png

18th Season


#18-4 Moscoviumと日本語フォント

 今回は、FPGAボード(Sipeed Lichee Tang Primer)のMoscoviumマイコンに、日本語(漢字)フォントROMを搭載しようというテーマです。

日本語(漢字)フォント考察

 昔(「#12-3 DUE+TFTで日本語表示」)、Arduino DUE+TFTシールドで考察したことがあるので、重複は避け、以下にまとめます。

 まさに、Flashメモリが512KバイトもあるDUEだから実現できた応用だったのですが、これをMoscoviumマイコン(FPGAボード)で実行できるか?と言うと、できません。
 メモリ(RAMマクロ)が全く足りないのです。FPGAボードの全RAMマクロを投入しても、128Kバイトにしかなりません。

※1トランジスタ/ビットのFlashメモリに比べて、FPGAボードのRAMはデュアルポートなので8トランジスタ/ビット程になるため、太刀打ちできません。

 これをMoscoviumマイコン(FPGAボード)で実現するには、メモリ使用量の削減が必要です。以下に、その削減案を示します。

 案1)及び2)を組み合わせて、結果、64Kバイト以下まで圧縮できたら、何とかFPGAボードのRAMマクロで賄うことが可能です。2)案でデータサイズは1/4、1)案でも1〜1/2程度まで圧縮可能なので、合わせ技で何とかなりそうな感触です。

コード体系

 これについても、「#12-3 DUE+TFTで日本語表示」で議論済みなので詳しくはそちらをご覧ください。

 コード体系はシフトJIS(S-JIS)が便利なので、これを採用します。

 S-JISから区点コードへの変換が必要となります。変換プログラムは、「#12-3 DUE+TFTで日本語表示」より、tft_kprint.inoの中で使ったtft_sjis2kuten()関数がそうなので、そちらを参照してください。
 このプログラム(tft_kprint.ino)でもそうですが、区点コードは2次元(区と点)のマトリクスで扱い難い為、0番からのシリアル番号に変換して取り扱います(下式)。

  区点シリアルコード=(<区>−1)×94+<点>−1
   …… 1≦<区、点>≦94、0≦区点シリアルコード<8,836=942

半角フォント

 半角フォントには対応しません。全角フォント8×8ドットに対して半角フォント4×8ドットでは、あまりに視認性が悪すぎるためです。
 ただし、半角のASCIIコードを指定された時に、漢字などと同じ8×8ドット(全角)のフォントを表示可能な様に工夫しておきます。

 具体的には、区点シリアルコードの0x0300〜0x03ff番にASCIIコード(0x00〜0xff)のフォントを入れておきます(下図)。

a184_ktasc.png

 上図赤枠で囲んだ所が、区点シリアルコードで0x0300〜0x03ff番に該当する部分です。区点コードの9区〜11区辺りに相当します(上図一番上に見えている行が1区)。
 元々、区点シリアルコードの0x0300番台は空き領域になっていて、有効な文字が存在しないため他の文字とは干渉しません。

 ASCIIコード範囲のフォントデータを取り出したい時には、<ASCIIコード>+0x0300を区点シリアルコードとするフォントを取ってくれば良いことになります。

日本語フォントユニット(FONTJP)

 DUEのプログラム(tft_kprint.ino)では、プログラムメモリ上にフォントデータを配置しました。
 Moscoviumの場合16ビットマイコン故、メモリ空間が64Kバイト分しかなく、現在のバスステートコントローラBUSC2040Dでは、RAM領域が最大40Kバイト、ROM領域が最大20Kバイトに制限されていて、メモリ空間にフォントROM 64Kバイトを配置するのは困難です。

 そこでMoscoviumマイコンでは、I/Oユニットの1つとして「日本語フォントユニット」を作り、メインメモリとは別空間にフォントROMを持たせます。I/OレジスタにS-JISコードを書き込むと、別なレジスタからフォントデータを読み出せるような仕組みにしようと思います。

目標仕様

 以下、日本語フォントFONTJPユニットの目標仕様をまとめます。

ブロック図

 ブロック図は以下の様になります。

a184_fontjp.png

 薄黄色の箱は、CPUからアクセス可能なI/Oレジスタです。レジスタの中に、その機能と関連する論理も含まれています。例えば、fnjpcodブロックにはS-JISコードから区点コードへの変換回路、fnjpdatブロックにはアフィン変換回路(後述)が含まれます。

I/Oレジスタ仕様

 以下表にI/Oレジスタ一覧を示し、その後に各レジスタの仕様を説明します。

Addr Name R/W Bit:15〜0 Memo
0xf0b0 fnjpctl RW SJ
S1
SJ
S2
KT
C
IN
V
FL
PH
FL
PV
ROT
[1:0]
font rom control
0xf0b2 fnjpcod RW FCOD[15:0] S-JIS(W) or KU-TEN(R) code
0xf0b4 fnjpdbl W FNTD[7:0] convert double
R DOBL[15:0]
0xf0b6 reserved
0xf0b8 fnjpdata R FDAT7[7:0] FDAT6[7:0] font rom data a
0xf0ba fnjpdatb R FDAT5[7:0] FDAT4[7:0] font rom data b
0xf0bc fnjpdatc R FDAT3[7:0] FDAT2[7:0] font rom data c
0xf0be fnjpdatd R FDAT1[7:0] FDAT0[7:0] font rom data d

 BUSC出力のセレクト信号はbcs_fnjp_nです。上表の範囲でアサートされるので、FONTJPユニット内では、アドレスbadr[3:0]をデコードしてレジスタを特定しています。このI/Oユニットでは、fnjpdata,fnjpdatb,fnjpdatc,fnjpdatdに対してはバイト/ワードアクセスが可能です。それ以外のレジスタは、必ずワードアクセスしてください。

アフィン変換回路

 前節レジスタ仕様に示した様に、90°毎の回転変換と、左右・上下反転(アフィン変換)をハードウェアで実行できるようにしておこうと思います。

 例えば、時計回り90°回転は、以下表の様になります。

レジスタ original font rotate 90°
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
fnjpdata [15:8] 63 62 61 60 59 58 57 56 7 15 23 31 39 47 55 63
[7:0] 55 54 53 52 51 50 49 48 6 14 22 30 38 46 54 62
fnjpdatb [15:8] 47 46 45 44 43 42 41 40 5 13 21 29 37 45 53 61
[7:0] 39 38 37 36 35 34 33 32 4 12 20 28 36 44 52 60
fnjpdatc [15:8] 31 30 29 28 27 26 25 24 3 11 19 27 35 43 51 59
[7:0] 23 22 21 20 19 18 17 16 2 10 18 26 34 42 50 58
fnjpdatd [15:8] 15 14 13 12 11 10 9 8 1 9 17 25 33 41 49 57
[7:0] 7 6 5 4 3 2 1 0 0 8 16 24 32 40 48 56

 表は8×8ドットのマトリクスとなっていて、レジスタ欄に、フォントデータを読み出し可能なfnjpdata〜fnjpdatdレジスタと、その上位・下位バイトが縦に並んでいます。
 マトリクス内に記載した数字は、読み出したフォントデータのビット番号63〜0です。青く着色したセルから、ビット値"1"が読めると思ってください。上表の例では、平仮名「あ」のフォントデータを読み出している状態です。

 左半分(original font)に示したフォントデータを時計回りに90°回転すると、右半分(rotate 90°)となるべきです。つまり、対応するビット番号(63〜0)が対応するレジスタから読める様、単にビット順番を組み替えれば良いことが解ります。
 他の左右・上下反転も同じです。

 すると、アフィン変換回路は以下図となります。

a184_affine.png

 ビットの組み替え回路(○に×の⨂回路)は論理セルを消費しませんが、セレクタMUXは、64ビット2 to 1セレクタとなるので、そこそこ大きい回路にはなります。しかし、この変換をソフトウェアで実現しようとしたら、大変です。一体、何百サイクル掛かるんだ?ってことです。ハードウェアで持たせておいた方が絶対良いはず!

 なお、複数のアフィン変換を組み合わせた場合の変換順番は、上図の通りとなっております。

 時計回り90°回転回路(図中ROT90)を1つ作っておくと、それを3個カスケードに接続するだけで、0°、90°、180°、270°の回転に対応することが出来ます。

RAMマクロ

 TD IDEのROMマクロは、RAMマクロをリードオンリで使っています。
 RAMマクロには、9KビットRAMマクロ(最大64個使用可能)と、32KビットRAMマクロ(最大16個使用可能)の2種類があります。

 Moscoviumマイコンに於いては、32KビットRAMマクロはCPUのメインメモリ(ROMおよびRAM)用として、最大でROM 20Kバイト+RAM 40Kバイトを使う場合があります。最大構成の場合に必要な32KビットRAMマクロ数は15個です。
 残り1個では4Kバイト分にしかならず、フォントROMに使うにはサイズ不足です。

 従って、フォントROM用としては9KビットRAMマクロを使うことになります。
 9KビットRAMマクロも、UART8N1の受信FIFOバッファや、LOGA8CHのキャプチャFIFOなどで使うため、全て使い切ってしまう様では、他のI/Oユニットとの同時使用が出来なくなります。

 TD IDEのIP Generatorを起動して、以下図の様にROMマクロを作成しておいてください。

a184_fnjprom.png

 この場合の9KビットRAMマクロ数は、上図にある通り57個(推定値)です。最大64個まで、7個ほど余裕がありますので、UART8N1等いくつかのI/Oユニットとは共存できると思います。

漢字フォントはどうする?

 第二水準までの文字で、ざっと7,000文字以上の漢字フォントを起こすのは大変……。気が遠くなりかけた時、福音がありました!フリーの8×8ドットフォントを提供してくれているHPを見つけたのです(↓)。

  Little Limit (別ウインドウが開きます)

 ありがたや。上HPから、「美咲フォント」を使わせていただこうと思います。

 以下、「美咲フォント」のMIFファイルを生成する手順です。

謝辞: しっかり第二水準までカバーした極小フォントを提供してくださっている「Little Limit」の作者(門真 なむ)様に感謝いたします。

完成したデザイン

 前節で完成させたFONTJPユニットを含む、MCOC115JP0408のデザインデータを以下リンクよりダウンロード可能です。FPGAボードへの書き込み手順はこちらを参照してください。

btn_moscovium.png


 以下に、コンパイル(論理合成・配置配線)結果をまとめておきます。

 FONTJPユニット単体でコンパイルしてみたところ、約1,000LUTと、かなり大きいことに驚きました。

 FONTJPユニット単体で1,000LUTは、ちょっと大きいけど、上の様に避けられない理由であることが判ったので、これを許容します。

RAMマクロの消費数量

 RAMマクロの消費数量について追加検討しておきます。

 一応、最大仕様として漢字コード第二水準までカバーできる様に、64ビット×8KワードのフォントROMとしましたが、不要な文字コード領域は省いて、なるべく小さいROMに収める様な努力はすべきです(RAMマクロ数は有限なので)。

 TD IDEのIP Generatorは賢くて、ROMデータとして喰わせるMIFファイルの中身に0x0000等(※)の固定データが連続した場合、その領域にはRAMマクロを配置せず、ちゃんとしたデータが詰まった部分にだけ、RAMマクロを配置します。

※0x0000以外の固定データの扱いについては、当方では確認しておりません。

 この為、スクリプト(fontjp_gen_mif.olv)実行時、スクリプト先頭付近の変数max_datに所望のワード数を設定しておくと、最小限のRAMマクロだけを消費して回路を構成することが出来ます。

 有意義な選択肢は以下2通りです。

  var max_dat=5*1024;  // 5Kワード=1区〜54区(第一水準+α)までカバー

 または、

  var max_dat=8*1024;  // 8Kワード=1区〜87区(第二水準)までカバー

 上の設定でMIFファイルを作ってコンパイル(論理合成・配置配線)した結果、使用した9KビットRAMマクロ数は、5Kワードで36個、8Kワードなら57個でした。MIFファイルを作り直すだけで、論理回路にも、ROMマクロにも、手を触れずにRAMマクロ数を削減することが出来るのがGoodです。
 RAMマクロは全部で64個まで使えるので、第二水準までカバーする8Kワードを選択しても、UART8N1等のI/Oユニットで使う分くらいは確保できます。もっと沢山のRAMマクロをFONTJPユニット以外のI/Oユニットで使いたい場合には、第一水準だけで諦める等の妥協をすると、占有使用するRAMマクロ数を減らすことが可能です。

小手調べの実験

 サンプルアプリケーションは、「#18-2 SPI通信する」で作成したプログラムのFONTJPユニット対応版です。FONTJPユニットからフォントデータを読み出して表示するように、ちょこっと改造するだけです。以下にソースファイルをリンクしておきます。

  FONTJPユニット対応版プログラム:flash_mesg.asm

 デフォルトでは従来通り、7ビットASCII(英数)フォントを使うようになっていて、以下の修正をしてアセンブルすると、FONTJPユニットを使って日本語(漢字)フォントを表示できるようになります。

  def f,""  // fontjp unit: not use="" / use="#"

    ↓下の様に変更すると、日本語フォントが表示できる。

  def f,"#"  // fontjp unit: not use="" / use="#"

 デザインがMCOC115JP0408に変わるだけで、FPGAボードと8×8 LEDなどとの接続に変更有りませんので、こちらを参考に、実験を進めてください。
 あと、日本語(漢字)の文字列を送信する時、文字コードがS-JISである必要があるので、UTF-8になってしまうArduino IDEのシリアルモニタは使えません。Tera Termなど、S-JIS送信対応の通信ソフトを使ってください。


 以下、実験中の様子です。

a184_expr.jpg

 8×8 LEDに「あ」と「花」を表示したところを撮影しました。上写真の方向で文字が読めるように、FONTJPユニットのアフィン変換機能を使って、時計回りに90°回転してあります(下コード)。

  // fontjp setting
  ldbiu r0,fnjp_rot_1  // 時計回りに90°回転
  ldwi r7,fnjpctl
  stw [r7],r0


 実は、本命の実験はSPI-TFTへ日本語表示する「次回」なので、今回の実験はあっさりと以上で終了します。


 次回、FPGAボード(Moscoviumマイコン)にSPI-TFTを接続して、日本語表示してみたいと思います。お楽しみに。


btn_arduino.png

btn_prev.png btn_next.png

home