その1 | 「AREA」命令 | PSoCのアセンブラではROMとRAMを区別するのに「AREA」命令を使用します。 |
その2 | インクルード・ファイル | シンボル定義は、インクルードファイルにして各ソース毎に読み込む |
その3 | 「MVI [[ext]++],A」命令 | 「MVI [[ext]++],A」命令を使用するとエラーになる |
その4 | 「.LITERAL」命令 | ROM内の文字列は「.LITERAL」命令で囲まないとエラーになる |
その5 | 「DWL」命令 | Designer4.2では「DWL」命令が誤動作する |
その6 | 演算結果の上位バイトを取り出せない | ラベル定義した値を演算後に上位バイトを取り出そうとすると、おかしな値が返される |
その7 | EEPROMユーザーモジュール | EEPROMユーザーモジュールで部分書き込みすると、スタックを103バイト消費する |
その8 | RAMで定義したラベル | RAMで定義したラベルをROM領域で使用するとエラーになる |
その |
ワンチップマイコンは、ROM/RAMの領域が同じメモリ空間にあるもの(H8 等)・別のメモリ空間にあるもの(Z8/AVR 等)が有りますが、PSoCは後者に属し ROMとRAMの領域が明確に区別されています。
そのため、アセンブラを使用するに当たり ROM空間とRAM空間を指定する疑似命令として「AREA」命令があります。
しかし、ソースファイルの冒頭で適当なエリア名をつけて領域を指定しようとしてもアセンブラはエラーを返してきます。エラーメッセージの内容は英語なので良くわからないのですが、宣言を"boot.asm"内で行うとエラーは発生しなくなります。
でも、PSoCのデバイスエディタで構成を変えると、"boot.asm"は新しく書き換えられてしまい AREA命令を再度書き直す必要が出てきます。
試行錯誤の結果、
とすることで、無事 領域を分けることができました。
ROM領域 "AREA text" RAM領域 "AREA bss"
プログラムが"main.asm"だけで済んでいるときは良いのですが、割り込み処理等を使用してソースが複数に分割される場合、ラベルをグローバル宣言しただけでは別のソースからラベルを読み取れない為 エラーが発生してしまいます。
また、同じラベルをソース毎に定義すると ラベルの重複定義でエラーになってしまいます。 (←良い子は こういうバグの元になりそうな方法を実行しては いけません!!)
この場合、インクルードファイル(例:"label.inc")を作成してラベルを定義し、各ソース毎に「include」命令を記述して 定義されたラベルを読み込むようにすると良いようです。
PSoCには「MVI [[ext]++],A」という命令があります。
この命令は、RAM[ext]で示されるアドレスにAレジスタの値を書き込み、その後[ext]の内容を+1する命令で、RAMを初期化する際等のRAMアドレス・ポインタとして使いやすいのですが、このままの書式でソースに書き込むと「命令がありません」というエラーになってしまいます。
データシートやアセンブラのマニュアルでは「MVI [[ext]++],A」と記載されているのですが、PSoC Designerのヘルプを見ると 「MVI [ext],A」という風に記載されており こちらのほうが正しい記述のようです。
マニュアル類の用例に「MVI [[ext]++],A」と記載するのは反則ですよね!
LCD等を接続すると 文字列をROMにセットする必要があります。文字列そのものは「ASCIZ」や「DS」命令で記述できますが、そのままではアセンブル時にエラーが発生してしまいます。
「.LITERAL」〜「.ENDLITERAL」命令で囲むとエラーは発生しなくなります。
PSoCDesigner4.2(SP2)ではリトルインディアンのワード定義「DWL」を使用すると数値が化けてしまいます。
Designer4.0では正常に展開されます。
PSoC Designer4.2(SP2)で演算結果の上位バイトを取り出そうとしても正しい値が取り出せません。色々と試してみた所、演算の優先順位を無視して左から順に計算しているようです。
EEPROMユーザーモジュールは フラッシュROMをEEPROMに見立てて使用できる便利なモジュールですが、
・1ブロックすべて使用する場合で32バイト
・1ブロックを部分書き込みすると103バイト
もスタックを消費します。
CY8C27443の場合、約半分のRAMを使用してしまうことになるのでRAMの使用量が増えていくと ある時 突然EEPROMモジュールがエラーを返すようになります。
エラーの戻り値が「FE」の場合、スタックが不足していることが考えられます。
私は これで1週間悩みました。
また、ユーザーモジュールの関数ですが、「デバイスエディタでEEPROMモジュールを配置する際に "First Block"に定義したブロックNo.を基準として 各関数でオフセットを指定して読み書きする」という使い方をしますが、"First Block"を0にすると 関数で指定したオフセット=ROMアドレス となります。
プログラムを書くときにORG命令でEEPROMとして使用する領域にデータをセットすると プログラムを書き込んだ際に自動的に初期値が書き込まれるようになるので(計算すればFirst Blockを定義しても同じですが...)使い勝手が良くなるように思います。
RAMの初期化でRAM領域で定義したラベル間の値を使用してループカウンタの初期値として使用することがありますが、このような使い方をすると「領域が違う」というエラーが発生します。
確かにRAMのラベルをそのまま使用するとバグの元になるのでエラーにしたい気持ちはわかるのですが、演算をした値はROM領域で使えるようにしてもらえるとありがたいです。