access logger

家庭コンピュータ環境の模索 >WP34sという電卓 >How to develop
最終更新: 2013-03-02


How to develop

  1. SVN checkout
  2. アセンブラでの開発
  3. クロス開発環境の構築
  4. How To Build
  5. 焼く
  6. QtGui

SVN checkout

開発成果は、sourceforge.net の SVN リポジトリ上に随時アップされる。開発に参加する場合は、リポジトリをチェックアウトしてくる。

$ svn co https://wp34s.svn.sourceforge.net/svnroot/wp34s wp34s

SVNコマンド便利帳

Subversion メモ
自分の変更点を調べる
svn diff filename
svn diff は .svn 領域にある「修正元リビジョンのコピー」に対して作業コピー中のファイルとの比較を行う。
svn diff -r rev filename とすると、rev の状態と比較する。
更新を取得する
svn update
状態を一覧する
svn status
手元で修正したファイルには "M" が付いている。
コミットログを見る
svn log -r 2000:2010 revision.txt2000から2010 までの revision.txt に関するログ。revision.txt は必ず更新されるので。

アセンブラでの開発

アセンブラのファイルは、trunk/xrom/ と、library/の下にあり、前者は、XROMとしてCのコードと一緒にオブジェクトにコンパイルされて組み込み関数となり、後者はライブラリ領域にバイトコードとしてコンパイルされる。ライブラリ領域も、LIB と BUP と RAM に別れる。LIB はソースコードの library/ 領域から来たもので、Cからできたオブジェクトコードと結合されて、ファームウエアとともに書き込まれる領域。BUP はユーザがキー入力したけど、バッテリを交換しても消えないフラッシュ領域。RAM はバッテリ交換によって失われるRAM領域である。

アセンブラは、キーストロークマクロをベースとしているが、XROM領域の組み込み関数を記述するための拡張もなされている。

特徴的なものが、オペコードを外部から読み込むことができるようになっていること。これによって、古いバージョンのバイナリを、古いオペコード表を使ってディスアセンブル→得られたアセンブラを、新しいオペコード表を使ってアセンブル。というように変換可能である。

V2.2 までは、ライブラリ領域はバンクわけされていたが、V3からはバンクわけされていない、単一のライブラリ領域となっている。

V3になり、多くの内蔵関数もXROMアセンブリで記述されてメモリを節約するようになっている(速度は劣る)。内蔵関数もユーザ拡張も同じ言語で記述されているというのは、Emacs と同様の思想を感じる。拡張言語は Lisp ではなく RPN だが。順序(演算子が前か後ろか)と道具(スタックかリストか)が違うだけで似たようなものか。

E24系列に丸めるマクロを作成することを例題に解説した

各ファイルのコマンドと意味は次のとおり。

trunk/xrom/

ファイル名説明
agm.wp34s
bessel.wp34s
beta.wp34s
common.wp34s
complex.wp34s
date.wp34s
derivative.wp34s
distributions/
distributions.wp34s
error-function.wp34s
fibonacci.wp34s
gudermannian.wp34s
integer.wp34s
integrate.wp34s
lambert_w.wp34s
modes.wp34sSETJPNなどのモードセット関数
next_prime.wp34s
orthopolys.wp34s
parallel.wp34s
percent.wp34s
permutations.wp34s
prodsum.wp34s
quadratic.wp34s
solve.wp34s
who.wp34sWHOコマンド。スタッフロール。
zeta.wp34s

library/

ファイル名説明
8queens.wp34s8queens_pp.wp34s のほうが、内容は同じでラベル付けされているのでわかりやすい。8クイーン問題の解の個数を求める。ベンチマーク用。デフォルトでは組み込まれない。http://www.hpmuseum.org/cgi-sys/cgiwrap/hpmuseum/articles.cgi?read=700によれば 2.1秒。
8queens_alias.wp34s
8queens_pp.wp34s
E24.wp34s自作
HHC2010_Challenge.wp34s
PF.wp34s
TRIGON.wp34s標準。[h][CAT][▲][▼]…LBL'TRI'[XEQ]と実行する。
[R/S]を押してゆけば、三辺の長さ(a,b,c)、3つの角(α、β、γ)を聞いてくる。入力は[R/S]。わからない値は空白でも良い。Solution: の後に、辺と角のすべての値を教えてくれる。
TVM.wp34s標準
berger.wp34s
code_breaker.wp34s
code_breaker_pp.wp34s
complexsolve.wp34s
complexsolve_alias.wp34s
coordinates.wp34s標準。三次元のxyzと極座標の間の変換。
coordinates_alias.wp34s
day_in_year.wp34s
derivative.wp34s
digamma.wp34s標準
fibonacci.wp34s
matrix.wp34s標準
matrixedit.wp34s標準
matrixtestAM01.wp34sマトリクスのテスト用。一般的に組み込まれない。
matrixtestAM02.wp34s
matrixtestAM03.wp34s
matrixtestAM08.wp34s
matrixtestAM10.wp34s
matrixtestAM11.wp34s
matrixtestAM12.wp34s
matrixtestAM13.wp34s
mod.wp34s
polyroot.wp34s
primesieve.wp34s
primesieve_pp.wp34s
product.wp34s
quadratic.wp34s
quaternions.wp34s
quaternions_alias.wp34s
savage.wp34s
solve.wp34s
sum.wp34s
vectors.wp34s標準

アセンブラの実行ファイルは、Windows 上では perl スクリプトを実行形式に変換したものが使われることが一般的だが、Linux 上では、実行属性を付けて、直接、perlスクリプトを実行すればよい。makelib.cmd を参考に、makelib.sh を書く。このシェルスクリプトによって、ライブラリ(wp34s-lib.dat)と、カタログ(library.cat)が生成され、エミュレータディレクトリや ROMファイル(calc_full_my.bin,calc_xtal_full_my.bin)に配置、結合される。

#!/bin/sh

cd library
DEBUG=0
TOOLS=../trunk/tools
ASM=${TOOLS}/wp34s_asm.pl
LIB="${TOOLS}/wp34s_lib.pl -d ${DEBUG}"
PP=${TOOLS}/wp34s_pp.pl

DIR1=../trunk/windows/wp34sgui
DIR2=../trunk/realbuild
DIR3=../trunk/QtGui/memory

DAT=wp34s-lib.dat

${LIB} -pp matrix.wp34s matrixedit.wp34s vectors.wp34s digamma.wp34s -olib ${DAT}
${LIB} TVM.wp34s -ilib ${DAT} -olib ${DAT}
${LIB} -cat -ilib ${DAT} >library.cat

cp ${DAT} ${DIR1}
cp ${DAT} ${DIR2}
cp ${DAT} ${DIR3}

cd ../trunk/realbuild
cat calc.bin ${DAT} > calc_full_my.bin
cat calc_xtal.bin ${DAT} > calc_xtal_full_my.bin

今、何が組み込まれているかは、library/library.cat にレポートされている。

$ cat library.cat
Initial library catalogue (format: flash file)
  Source: wp34s-lib.dat, Program name: E24, Line number: 1
  Source: wp34s-lib.dat, Program name: G[->]C, Line number: 219
  Source: wp34s-lib.dat, Program name: M-1, Line number: 310
  Source: wp34s-lib.dat, Program name: MED, Line number: 441
  Source: wp34s-lib.dat, Program name: MIO, Line number: 548
  Source: wp34s-lib.dat, Program name: PF, Line number: 580
  Source: wp34s-lib.dat, Program name: TRI, Line number: 610
  Source: wp34s-lib.dat, Program name: TVM, Line number: 893
  Source: wp34s-lib.dat, Program name: Vec, Line number: 1313
  Source: wp34s-lib.dat, Program name: [PSI], Line number: 1453
Library details:
// WP 34S assembly preprocessor enabled: '-pp'
// Opcode map source: ../trunk/tools/wp34s.op
// Opcode SVN version: -- unknown --
// Running WP 34S preprocessor from: ../trunk/tools/wp34s_pp.pl
// WP 34s version: 32
// CRC16: 35D7
// Running in V3 Flash-mode. Max words: 9999
// Total words: 1675
// Total steps: 1590

クロス開発環境の構築

  1. ビルドに必要なライブラリを入れる。MPC はパッケージが無いのでソースから入れる。GMP が古すぎて MPC がコンパイルできないので、それも入れ直し。ついでに、MPFRも入れ直し。PPL と GLooG もついでにいれておく。PPL は時間がかかるので覚悟しよう。
    [/usr/local/src]$ tar xvzf gmp-5.0.2.tar.bz2
    [/usr/local/src]$ cd gmp-5.0.2
    [/usr/local/src/gmp-5.0.2]$ CPPFLAGS=-fexceptions ./configure --enable-cxx
    [/usr/local/src/gmp-5.0.2]$ make
    [/usr/local/src/gmp-5.0.2]$ make check | grep XPASS
    [/usr/local/src/gmp-5.0.2]$ sudo make install
    [/usr/local/src/gmp-5.0.2]$ cd ..
          
    PPL で例外を使うために、configure を上記のようにする。
    [/usr/local/src]$ tar xvzf mpfr-3.1.0.tar.gz
    [/usr/local/src]$ cd mpfr-3.1.0
    [/usr/local/src/mpfr-3.1.0]$ ./configure --with-gmp=/usr/local
    [/usr/local/src/mpfr-3.1.0]$ make
    [/usr/local/src/mpfr-3.1.0]$ make check > check.log
    [/usr/local/src/mpfr-3.1.0]$ sudo make install
    [/usr/local/src/mpfr-3.1.0]$ cd ..
    
    [/usr/local/src]$ tar xvzf mpc-0.9.tar.gz
    [/usr/local/src]$ cd mpc-0.9
    [/usr/local/src/mpc-0.9]$ ./configure --with-gmp=/usr/local --with-mpfr=/usr/local
    [/usr/local/src/mpc-0.9]$ make
    [/usr/local/src/mpc-0.9]$ make check > check.log
    [/usr/local/src/mpc-0.9]$ sudo make install
    [/usr/local/src/mpc-0.9]$ cd ..
          
    うまくいかないので、結局 PPL と GLooG は使わないことにした。最適化性能が劣化する?
  2. binutils をビルド。
    [/usr/local/src]$ tar xvzf binutils-2.21.tar.gz
    [/usr/local/src]$ cd binutils-2.21
    [/usr/local/src/binutils-2.21]$ mkdir build
    [/usr/local/src/binutils-2.21]$ cd build
    [/usr/local/src/binutils-2.21/build]$ ../configure --prefix=/usr/local/arm-none-eabi --program-prefix=arm-none-eabi- --target=arm-none-eabi --enable-interwork --enable-multilib
    [/usr/local/src/binutils-2.21/build]$ make
    [/usr/local/src/binutils-2.21/build]$ make insatll
    [/usr/local/src/binutils-2.21/build]$ cd ../..
          
    /usr/local/arm-none-eabi/ にインストールされる。あらかじめ書き込みできるようにディレクトリを作成しておく。
    [/usr/local/src]$ export PATH=/usr/local/arm-none-eabi/bin:$PATH
    [/usr/local/src]$ export LD_PRELOAD_PATH=/usr/local/lib:$LD_PRELOAD_PATH
    [/usr/local/src]$ export LD_RUN_PATH=/usr/local/lib:$LD_RUN_PATH
          
    そこにパスを通しておく。
  3. newlib のソースを展開しておく。
    [/usr/local/src]$ tar xvzf newlib-1.19.0.tar.gz
          
  4. 本番。gcc。libstdc++ とか時間がかかるので、C だけに絞った。
    [/usr/local/src]$ tar xvzf gcc-4.6.2.tar.gz
    [/usr/local/src/gcc-4.6.2]$ mkdir build
    [/usr/local/src/gcc-4.6.2]$ cd build
    [/usr/local/src/gcc-4.6.2/build]$ ../configure --prefix=/usr/local/arm-none-eabi --program-prefix=arm-none-eabi- --target=arm-none-eabi --with-newlib --with-headers=/usr/local/src/gccc-4.6.2/newlib/libc/include --enable-interwork --enable-multilib --with-gmp=/usr/local --with-mpfr=/usr/local --with-mpc=/usr/local --enable-languages=c --disable-shared
    [/usr/local/src/gcc-4.6.2/build]$ make all-gcc
    [/usr/local/src/gcc-4.6.2/build]$ make install-gcc
    [/usr/local/src/gcc-4.6.2/build]$ cd ../..
          
    まずは、第一段階。
  5. newlib
    [/usr/local/src]$ cd newlib-1.19.0
    [/usr/local/src/newlib-1.19.0]$ mkdir build
    [/usr/local/src/newlib-1.19.0]$ cd build
    [/usr/local/src/newlib-1.19.0/build]$ ../configure --target=arm-none-eabi --prefix=/usr/local/arm-none-eabi --with-mpc=/usr/local --with-mpfr=/usr/local --with-gmp=/usr/local --enable-interwork --enable-multilib
    [/usr/local/src/newlib-1.19.0/build]$ make
    [/usr/local/src/newlib-1.19.0/build]$ make install
    [/usr/local/src/newlib-1.19.0/build]$ cd ../..
          
  6. もういちど gcc
    [/usr/local/src]$ cd gcc-4.6.2/build
    [/usr/local/src/gcc-4.6.2/build]$ make
    [/usr/local/src/gcc-4.6.2/build]$ make install
          
  7. 使ったビルドスクリプト。build-req.shbuild-cross.sh

How To Build

まずはソースコードの構造について。

ベースとなるソースコードは trunk/ 以下に入っている。この中には、コアとなる C で書かれたコードと、アセンブラで書かれた trunk/xrom/ 以下のコードからなる。これらはコンパイルされて、trunk/realbuild/calc.bin となる。これに、library/ 以下のコードが結合されると trunk/realbuild/calc_full.bin ができあがる。これを、sam-ba 経由で焼きこむことになる。

それぞれの実行ファイルは、{アーキテクチャ名}_{ツール名}というディレクトリの下にできる。つまり、Linux_qt/ の下には、Linux(32bit)での Qt 関係の、Linux64_realbuild/ の下には、Linux64 環境で、ファームを作るためのツールの実行ファイルが、realbuild/ の下には実際に ROM に焼き込まれるファームが作られる。

ビルドスクリプトとしては、flash.cmd という MS-Windows 用のバッチファイルが配布されているが、これを改変して、flash.sh として使う。

#!/bin/sh

PATH="/usr/local/arm-none-eabi/bin:/usr/lib/qt4/bin:$PATH"

cd trunk
make REALBUILD=1 version all > ../flash-build.log 2>&1
make REALBUILD=1 XTAL=1 all >>../flash-build.log 2>&1

cd ..
./makelib.sh
echo NORMAL:
cat trunk/realbuild/summary.txt
echo XTAL:
cat trunk/realbuild/summary_xtal.txt

ここから呼ばれている、makelib.sh は、makelib.cmd を改変した、ライブラリビルドスクリプトである。

#!/bin/sh

cd library
DEBUG=0
TOOLS=../trunk/tools
# ASM="${TOOLS}/wp34s_asm.pl -op ${TOOLS}/wp34s.op -fill 0xffff"
ASM=${TOOLS}/wp34s_asm.pl
LIB="${TOOLS}/wp34s_lib.pl -d ${DEBUG}"
PP=${TOOLS}/wp34s_pp.pl

DIR1=../trunk/windows/wp34sgui
DIR2=../trunk/realbuild
DIR3=../trunk/QtGui/memory

DAT=wp34s-lib.dat

${LIB} -pp matrix.wp34s matrixedit.wp34s vectors.wp34s digamma.wp34s -olib ${DAT}
${LIB} TVM.wp34s -ilib ${DAT} -olib ${DAT}
${LIB} -cat -ilib ${DAT} >library.cat

cp ${DAT} ${DIR1}
cp ${DAT} ${DIR2}
cp ${DAT} ${DIR3}

cd ../trunk/realbuild
cat calc.bin ${DAT} > calc_full_my.bin
cat calc_xtal.bin ${DAT} > calc_xtal_full_my.bin

trunk/ ディレクトリに、主 Makefile がある。REALBUILD=1 とすると、クロスコンパイラが動作して、焼きこみ用のファームウエアができあがる。XTAL=1 とすると、立ち上がり時からクリスタルが有効になる。XTAL=1 としていなくても、[ON]+[C]+[C]で手動で有効にできる。また、XTAL=1 のときは、ストップウォッチが有効になるように features.h で設定されている。

REALBUILD=1 を付けずに、単に make としただけでは、セルフコンパイラが動作して、trunk/Linux/calc にコンソールエミュレータが作成される。

make qt_gui としたときには、セルフコンパイラが動作して、trunk/QtGui/Linux/WP-34s というQtGUI エミュレータが作成される。Qtエミュレータについては後述。ここでポイントになるが、エミュレータと実機用ファームウエアは同じソースコードから生成されるということである。エミュレータは実機のファームウエアをエミュレーションするものではない。ただし、ライブラリファイルは、アセンブラでバイナリにしたあと、実機の場合は主バイナリと結合して焼きこまれるが、エミュレータの場合はメニューからファイルとして読みこませる。それ以外にも、qt_gui_no_serial と言った仮想ターゲットもあるので、Makefile を参照のこと。

いずれの場合でも、定数生成システム、フォント生成システム、xrom 組み込みシステムが使われる。これらは、セルフコンパイラでツールを生成し、そのツールがコードを生成し、それで電卓が動作するシステムだ。

xrom 組み込みシステムは、ライブラリと同じアセンブラで内部関数を記述する仕組み。trunk/xrom/ 以下のファイルを -c オプション付きのアセンブラで、C のメモリイメージ(xrom.c)に変換して、本体のファームとして結合される。

基本数値演算としては、decNumber が使われる。これは SVN で配布されているが ICU(International Components for Unicode)で開発されたものを改変したもの。BCDベースの浮動小数点表現である。二進表現ではなく10進表現をベースに用いることにより、二進10進変換に伴う誤差を防げる。

feature.h

trunk/feature.h というファイルがあり、いろいろな #define をすることによって、コンパイル時の機能を選択することができる。その中で気に入っているものを紹介する。

#if !defined(REALBUILD) && !defined(WINGUI) && !defined(QTGUI) && !defined(IOS)
#define CONSOLE
#endif

なんか、IOSとかいう文字列が。

// Define this to support a STOPWATCH function like the StopWatch on the HP-41C
// Time Module or the HP-55
#if !defined(REALBUILD) || (defined(XTAL) /* && !defined(INFRARED) */)
#define INCLUDE_STOPWATCH
#else
//#define INCLUDE_STOPWATCH
#endif

ここからも、XTAL が定義されていれば、自動的に STOPWATCH が ON になることがわかる。

// Make EEX key enter PI if pressed when command line empty
#define INCLUDE_EEX_PI

標準だと、πは[h][EEX]に割り当てられているが、それが明らかな場合、シフトなしで[EEX]を押したらπが入力される。

// Turn on constant y-register display (not just for complex results)
#define INCLUDE_YREG_CODE

ドットマトリクス部に y レジスタの値が表示される。これも、なんで標準では無いのだろう?というレベル。

焼く

実績

Vine Linxu 5.2 + sam-ba linux版(atmel 配布)×libgcc のバージョンが古い(4.1.2)。atmel は 4.2.0を要求。
vmplayer(3.0.1) + Windows XP + MySamba.exe×
vmplayer(3.1.5) + Windows XP + MySamba.exe
Vine 5.2 + Wine + MySamba.exe×
Windows7 + MySamba.exe
Ubuntu 11.10 + wine + MySamba.exe
wine から serial を使うには、次のようにリンクを張る。
ln -s /dev/ttyUSB0 ~/.wine/dosdevices/com1
QtFlash(Linux,32bit)
  1. すでに WP-34s になっているなら、[ON]を押しながら[D]でデバッグモードになる(小さい"="が表示される)。
  2. [ON] + [S] + [S] でフラッシュ受付状態。SAM-BA? Boot と表示される。
  3. ケーブルを繋ぐ。
  4. ケーブルの "RESET" を押して離す。
  5. 本体の [ON] を押して離す。
  6. MySamba.exe で書き込み。
  7. ケーブルの "RESET" を押して離す。
  8. 本体の [ON] を押して離す。
  9. ケーブルを離す。
  10. [h][P.FCN]...(RESET) でリセットをしないと、STO などで数字引数が入らない。

QtGui

従来は Windows版のエミュレータのみ存在したが、Qtを使ったマルチプラットフォームのエミュレータの開発も、それと並行して進んでいる。いちいち本体に書いていてはメンドウなので、最終確認以外はエミュレータを使うのが望ましい。

  1. trunk/ ディレクトリで、make qt_gui として、QtGui対応のエミュレータができあがる。必要であれば、QMAKESPEC 環境変数を適切に設定すること。
  2. wine で trunk/windows/bin/wp34sgui.exe を起動して、メモリファイル wp34s.dat を作成する。
  3. trunk/QtGui/ ディレクトリで、./Linux/QtGui -devとして起動する。-dev オプションをつけると、スキンファイルをホームディレクトリからではなく、起動ディレクトリから見つけてくれる。trunk/QtGui/Linux/ ディレクトリから起動すると skin ファイルを見つけられない。
  4. Edit → Preference メニューから、メモリファイルのありかを指定する。trunk/QtGui/memory/ を作成して、さっき作成した wp34s.dat をコピーしてくる。また、trunk/realbuild/ から wp34s-*.dat もコピーしてくる。
  5. 最近のバージョンでは、Debug メニューから Show Debugger を選べば、右横にスタック状態を表示してくれるようになる。また、Edit → Preference で、Keyboardタブに Use H-shift click というオプションがある。これは、キーの下半分(緑文字)を押したら、H シフトを押してからそのボタンを押したことになる機能。ボタン押し回数がひとつ減るので使いやすいが押し間違いには注意。
  6. 最近、QtGui に serial port モジュールが加わった。QtGui/SerialPort.txt を読めばわかるが、なぜかバイナリが付属してくる。Mercurial(hg)でソースを取ってきて、static library を構築し直さなければならない。正直めんどくさい。
    1. 無ければ、 Mercurialをインストールする。
    2. ソースを取ってくる。
      hg clone https://code.google.com/p/qextserialport
    3. src/src.proCONFIG += staticlibのコメントを外す。
    4. wp34s/trunk/QtGui/SerialPort.txt の記述にしたがって、qextrerialport/src/posix_qextserialport.cppの762行目にパッチを当てる。
      ###########################################
      IMPORTANT: at the time I write this, there is a bug in qextserialport preventing
       it to be used with the WP-34s emulator.
      Line 762 of posix_qextserialport.cpp, flush is implemented as:
      
       tcflush(fd, TCIOFLUSH);
       
      But tcflush clears the buffers without sending or receiving their contents. This
       lead to byte loss. 
      This line must be replaced by:
      
       tcdrain(fd);
       
      And qextserialport recompiled. This apply only to the Mac & Linux version  
      ###########################################
      	
      これぐらい、パッチファイルをいれておいて欲しかったぜ。
    5. qmake; make でビルド。
    6. src/build/libqextserialport.a を wp34s/trunk/QtGui/serial/lib/Linux/libqextserialport.a に上書きする。

シリアル通信をするためには、まずポートの設定をする必要がある。ttyUSB0 を選べば良い、というのは落とし穴。/dev/ttyUSB0 とタイプしてやる必要がある。sudo でシリアルポートの書き込み権限を取得して、WP-34s -dev を起動する。

sudo LC_ALL=C ./Linux/WP-34s -dev

受け手側で、[h][P.FCN] (RECVを選択) [XEQ]で待ち受け状態。送る側は、SENDP, SENDA などのコマンドを実行する。

QtGui

[] [簡易マニュアル] [E24マクロの作り方] [コレクション]



近藤靖浩
Last modified: Sat Apr 26 12:06:48 JST 2014