家庭コンピュータ環境の模索 >WP34sという電卓 >How to develop
最終更新: 2013-03-02
開発成果は、sourceforge.net の SVN リポジトリ上に随時アップされる。開発に参加する場合は、リポジトリをチェックアウトしてくる。
$ svn co https://wp34s.svn.sourceforge.net/svnroot/wp34s wp34s
アセンブラのファイルは、trunk/xrom/ と、library/の下にあり、前者は、XROMとしてCのコードと一緒にオブジェクトにコンパイルされて組み込み関数となり、後者はライブラリ領域にバイトコードとしてコンパイルされる。ライブラリ領域も、LIB と BUP と RAM に別れる。LIB はソースコードの library/ 領域から来たもので、Cからできたオブジェクトコードと結合されて、ファームウエアとともに書き込まれる領域。BUP はユーザがキー入力したけど、バッテリを交換しても消えないフラッシュ領域。RAM はバッテリ交換によって失われるRAM領域である。
アセンブラは、キーストロークマクロをベースとしているが、XROM領域の組み込み関数を記述するための拡張もなされている。
特徴的なものが、オペコードを外部から読み込むことができるようになっていること。これによって、古いバージョンのバイナリを、古いオペコード表を使ってディスアセンブル→得られたアセンブラを、新しいオペコード表を使ってアセンブル。というように変換可能である。
V2.2 までは、ライブラリ領域はバンクわけされていたが、V3からはバンクわけされていない、単一のライブラリ領域となっている。
V3になり、多くの内蔵関数もXROMアセンブリで記述されてメモリを節約するようになっている(速度は劣る)。内蔵関数もユーザ拡張も同じ言語で記述されているというのは、Emacs と同様の思想を感じる。拡張言語は Lisp ではなく RPN だが。順序(演算子が前か後ろか)と道具(スタックかリストか)が違うだけで似たようなものか。
各ファイルのコマンドと意味は次のとおり。
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.wp34s | SETJPNなどのモードセット関数 |
next_prime.wp34s | |
orthopolys.wp34s | |
parallel.wp34s | |
percent.wp34s | |
permutations.wp34s | |
prodsum.wp34s | |
quadratic.wp34s | |
solve.wp34s | |
who.wp34s | WHOコマンド。スタッフロール。 |
zeta.wp34s | |
library/
ファイル名 | 説明 |
---|---|
8queens.wp34s | 8queens_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
[/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 は使わないことにした。最適化性能が劣化する?
[/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そこにパスを通しておく。
[/usr/local/src]$ tar xvzf newlib-1.19.0.tar.gz
[/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 ../..まずは、第一段階。
[/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 ../..
[/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
まずはソースコードの構造について。
ベースとなるソースコードは 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進変換に伴う誤差を防げる。
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) | ○ |
従来は Windows版のエミュレータのみ存在したが、Qtを使ったマルチプラットフォームのエミュレータの開発も、それと並行して進んでいる。いちいち本体に書いていてはメンドウなので、最終確認以外はエミュレータを使うのが望ましい。
hg clone https://code.google.com/p/qextserialport
########################################### 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 ###########################################これぐらい、パッチファイルをいれておいて欲しかったぜ。
シリアル通信をするためには、まずポートの設定をする必要がある。ttyUSB0 を選べば良い、というのは落とし穴。/dev/ttyUSB0 とタイプしてやる必要がある。sudo でシリアルポートの書き込み権限を取得して、WP-34s -dev を起動する。
sudo LC_ALL=C ./Linux/WP-34s -dev
受け手側で、[h][P.FCN] (RECVを選択) [XEQ]で待ち受け状態。送る側は、SENDP, SENDA などのコマンドを実行する。
[↑] [簡易マニュアル] [E24マクロの作り方] [コレクション]