新しいコード用のスペースを確保するために、コードを最適化する必要があります。すべての変更のためのスペースがありません。コードバンク切り替え(80c31 with 64k)が使えません。
7 に答える
ここでは多くのことを説明していませんが、考慮できる主な最適化レベルが 2 つあります。
マイクロ最適化: 例。MOV A,0 の代わりに XOR A Adam はこれらのいくつかを以前にうまくカバーしました。
マクロ最適化: プログラムの構造、使用されているデータ構造とアルゴリズム、実行されたタスクを見て、これらをどのように再配置したり削除したりできるかについて非常によく考えてください。実際に使用されていないコードのチャンクはありますか? あなたのコードは、ユーザーが目にすることのないデバッグ出力ステートメントでいっぱいですか? 一般リリースから除外できる単一の顧客に固有の機能はありますか?
それをうまく処理するには、どこでメモリが使い果たされているかを調べる必要があります。リンカー マップは、これを開始するのに適した場所です。マクロ最適化は、大きな勝利を収めることができる場所です。
余談ですが、優れた最適化 C コンパイラを使用して、コードの一部を書き直してみてください。コードがいかにタイトであるかに驚かれるかもしれません。真のアセンブラーのホットショットはそれを改善できるかもしれませんが、ほとんどのコーダーよりも簡単に優れている可能性があります. 約 20 年前にIARを使用しましたが、靴下が吹き飛ばされました。
申し訳ありませんが、遅くなってしまいましたが、かつてはまったく同じ問題があり、何度も問題が再発してきました。私の場合、プロジェクトは8051ファミリプロセッサの電話であり、ROM(コード)メモリを完全に使い果たしていました。経営陣が新機能を要求し続けたため、それは私に戻ってきました。そのため、各新機能は2段階のプロセスになりました。1)古いものを最適化して部屋を作ります2)今作った部屋を使い切って、新しい機能を実装します。
最適化には2つのアプローチがあります。戦術的および戦略的。戦術的最適化は、マイクロ最適化のアイデアで一度に数バイトを節約します。私はあなたが物事をどのようにやっているかについてより根本的な再考を含む戦略的な最適化が必要だと思います。
私が覚えている何かが私のために働き、あなたのために働くことができました。
あなたのコードがしなければならないことの本質を見て、いくつかの本当に強力で柔軟なプリミティブ操作を抽出してみてください。次に、プリミティブを呼び出す以外に低レベルがまったく実行されないように、トップレベルのコードを再構築します。理想的にはテーブルベースのアプローチを使用します。テーブルには次のようなものが含まれます。入力状態、イベント、出力状態、プリミティブ....つまり、イベントが発生したときに、テーブル内のセルで現在の状態のイベントを検索します。そのセルは、(オプションで)どの新しい状態に変更し、どのプリミティブ(存在する場合)を実行するかを示します。異なるレイヤー/サブシステムに対して、状態/イベント/テーブル/プリミティブの複数のセットが必要になる場合があります。
このアプローチの多くの利点の1つは、特定の問題に対応するカスタム言語を構築することと考えることができることです。この場合、テーブルを変更するだけで、非常に効率的に(つまり、最小限の追加コードで)新しい機能を作成できます。
申し訳ありませんが、私は数か月遅れており、とにかくこの過激なことをする時間がなかったでしょう。私はあなたがすでに同様のアプローチを使用していたことを知っています!しかし、私の答えは、いつか知っている誰かを助けるかもしれません。
アセンブリ言語では、手動で最適化する必要があります。ここにいくつかのテクニックがあります:
注: IANA8051P (私は 8501 プログラマーではありませんが、他の 8 ビット チップで多くのアセンブリを行ってきました)。
どんなに小さくても重複したビットを探してコードを調べ、それらを機能させます。
より珍しい命令のいくつかを学び、それらを使用して最適化できるかどうかを確認してください。MOV A,0 の代わりに XOR A を使用してアキュムレータをクリアすると、1 バイト節約できます。
もう1つの巧妙なトリックは、戻る前に関数を呼び出す場合、次の代わりにジャンプするだけです。
CALL otherfunc
RET
ただ行う:
JMP otherfunc
可能な限り相対ジャンプとブランチを実行していることを常に確認してください。絶対ジャンプよりもメモリの使用量が少なくて済みます。
今のところ頭のてっぺんから思いつくのはこれだけです。
打ちのめされた部門では、コードの一部を圧縮し、特定の時点でアクティブに使用される一部の部分のみを解凍しておくことも検討できます。圧縮/解凍システムに必要なコードが 8051 の小さなメモリの一部を占めるほど小さいとは信じがたいですが、わずかに大きなシステムでは驚異的に機能します。
さらに別のアプローチは、バイトコード形式または一部のステート マシン ツールが出力する種類のテーブル駆動型コードに変換することです。マシンにアプリの動作を理解させ、完全に理解できない実装を生成することは、コストを節約するための優れた方法です。部屋 :)
最後に、コードが実際に C でコンパイルされている場合は、さまざまなオプションを使用してコンパイルし、何が起こるかを確認することをお勧めします。また、私は 2001 年に ESC のコンパクトな C コーディングに関する記事を書きましたが、これはまだかなり最新です。小型マシンのその他のトリックについては、そのテキストを参照してください。
すでに述べた (多かれ少なかれ) 明らかな最適化に加えて、ここに本当に奇妙な (そして達成するのはほとんど不可能な) ものがあります: コードの再利用です。コードの再利用とは、通常の再利用を意味するのではなく、a) コードをデータとして再利用するか、b) コードを他のコードとして再利用することです。おそらく、asm hex オペコードで表現できる lut (または任意の静的データ) を作成できます (ここでは、ハーバードとフォン ノイマン アーキテクチャを比較する必要があります)。
もう 1 つは、コードに別のアドレスを指定すると、コードに別の意味を与えることで、コードを再利用します。ここに、私が何を意味するかを明確にするための例を示します。コードのバイトが次のようになっている場合: アドレス X の AABCCCDDEEFFGGHH で、各文字が 1 つのオペコードを表す場合、X+1 にジャンプすることを想像してください。たぶん、スペースで区切られたバイトが新しいオペコードを形成する完全に異なる機能を取得するかもしれません: ABC CCD DE EF GH.
ただし、注意してください: これは達成するのが難しい (おそらく不可能である) だけでなく、維持するのも恐ろしいことです。したがって、デモ コード (または同様のエキゾチックなもの) でない場合は、前述の他の方法を使用して mem を保存することをお勧めします。
1) 可能であれば、変数を xdata ではなく Idata に保存します
2) Jmp ステートメントを調べます - SJmp と AJmp を利用します
書き込み/準拠して「メモリ不足」エラーが発生したため、適合しないことがわかっていると思います。:) 回答はあなたの質問にかなり正確に答えているようです。コード例を取得するのが不足しています。
ただし、いくつかの追加の考えをお勧めします。
- すべてのコードが実際 に使用されていることを確認してください -- コード カバレッジ テスト? 未使用のサブスクは大きな勝利です -- これは難しいステップです -- あなたが元の作者であれば、それはより簡単かもしれません -- (まあ、多分) :)
- 「検証」と初期化のレベルを確認してください。変数/メモリを初期化したことを保証することに熱心になりすぎる傾向があり、十分に正しいと確信している場合があります。初期化しないでくださいとは言いませんが (duh)、メモリの移動を行う場合、宛先を最初にゼロに
する必要はありません。
1 --
- 新機能を評価する -- 既存のサブシステムを拡張して両方の機能をカバーできるか、または既存の機能を置き換えることができるか?
- 大きなコードの一部が新しい小さなコードの作成を節約できる場合は、大きなコードを分割します。
または、おそらく現在、ハードウェア バージョン 2.0 の議論がテーブルにあるかもしれません ... :)
よろしく