私は最近、アマチュアの愛好家としてロジック レベルの設計に取り組み始めましたが、今では自分の能力がはるかに劣るソフトウェアに直面していることに気付きました。Etienne Sicard による論文「A Very Simple Microprocessor」に基づいて、Logisim でカスタム 4 ビット CPU の設計を大まかに完了しました。私が組み込んだ非常に限られた機能 (加算、論理 AND、OR、および XOR) を、検出可能なバグ (交差指) なしで実行できるようになったので、プログラムを作成するという問題に直面しています。Logisim には、16 進数のスクリプトを RAM または ROM モジュールにインポートする機能があるため、独自のマイクロ命令コードを使用してプログラムを作成できますが、どこから始めればよいでしょうか? 私は文字通り、ソフトウェア設計の最も基本的なレベルにあり、ここからどこへ行くべきか本当にわかりません。この低レベルのプログラミングについて学習するためのリソースに関する良い提案、またはここから何を試すべきかに関する提案はありますか? 事前に感謝します。これはおそらく、このフォーラムでこれまでに尋ねられた最も直接的な質問ではないことを知っています.
3 に答える
私はあなたが言及した論文を知りません。しかし、独自のカスタム CPU を設計した場合、そのためのソフトウェアを作成する場合は、a) マシン コードで作成するか、b) 独自のアセンブラーを作成するかの 2 つの選択肢があります。
明らかに私はbに行きます。これには、ギアを少しシフトして、高度なプログラミングを行う必要があります。作成しようとしているのは、PC 上で実行され、単純なアセンブリ言語をカスタム マシン コードに変換するアセンブラ プログラムです。アセンブラ自体が高水準プログラムになるため、文字列操作とバイナリ操作の両方が得意な高水準プログラミング言語で記述することをお勧めします。私はパイソンをお勧めします。
基本的に、アセンブラが次のようなテキスト ファイルを読み取れるようにする必要があります。
mov a, 7
foo:
mov b, 20
add a, b
cmp a, b
jg foo
(私はこのプログラムを作っただけです。ナンセンスです。)
そして、コードの各行をその命令のバイナリ パターンに変換し、バイナリ ファイル (または、マイクロコントローラーが 16 進値を読み取ることができると言ったので、おそらく 16 進ファイル) を出力します。そこから、プログラムを CPU にロードできます。
だから、私はあなたをお勧めします:
- マシンがサポートする各オペコードの単純な記述表現であるアセンブリ言語を (紙の上で) 思いつく (すでにこれを行っている可能性があります)。
- 簡単なPythonを学び、
- 一度に 1 行ずつ読み取り (
sys.stdin.readline()
)、それがどのオペコードで、どのような値が取られるかを判断し、対応するマシン コードを stdout に出力する Python スクリプトを作成します。 - CPU で実行されるアセンブリ言語でアセンブリ コードを記述します。
楽しいプロジェクトのようですね。
私はあなたが面白いと思うかもしれない似たようなことをしました。また、独自の CPU 設計をゼロから作成しました。これは、可変長命令を備えたハーバード アーキテクチャに基づく 8 ビット マルチサイクル RISC CPU です。
Logisim で開始し、Verilog ですべてをコーディングし、FPGA で合成しました。
あなたの質問に答えるために、プログラム (命令、ニーモニック + データ) を対応する機械語に変換し、PROG メモリにロードできる単純で基本的なアセンブラを作成しました。私はシェルスクリプトでそれを書きました.awkを使用していますが、これは私が慣れていたものです.
私は基本的に 2 つのパスを実行します。最初に、ニーモニックを対応するオペコードに変換し、データ (オペランド) を 16 進数に変換します。ここで、すべてのラベル アドレスを追跡します。2 回目のパスでは、すべてのラベルが対応するアドレスに置き換えられます。(ラベルとアドレスはジャンプ用です)
アセンブラを含むすべてのプロジェクトは、https ://github.com/adumont/hrm-cpu で文書化されています。
命令セットは非常に小さく、mguica の回答のスレッドに基づいているため、次のステップは、命令セットを続行および/または完全にテストすることです。フラグはありますか?分岐指示はありますか。とりあえず、マシンコードを手動で生成します。フラグ、特にオーバーフロー (V) ビットは注意が必要です。msbit加算器のキャリーインとキャリーアウトを調べて、正しく理解する必要があります。命令セットは十分に小さいため、連続した命令のさまざまな組み合わせを試すことができ、その後に or とその後に xor とそれに続いて add、またはその後に and または 後に xor などを実行できます。フラグに戻り、たとえば、xor および or がキャリーとオーバーフローに触れていない場合は、キャリーとオーバーフローがゼロであり、論理命令によって触れられておらず、キャリーとオーバーフローが 1 で触れられていないことを確認し、キャリーとオーバーフローが分離されていることを個別に示します。 1対1、論理に触れないなど。すべての条件分岐がその1つの条件でのみ動作するようにし、両方の状態で無視されるフラグビットを使用してさまざまな条件分岐に導き、条件分岐がそれらを確実に無視するようにします。また、条件分岐がそれらを変更することになっていない場合は、そうでないことを確認してください。同様に、条件が条件付きフラグに触れないという分岐を引き起こさない場合... すべての条件付き分岐がその 1 つの条件でのみ動作することを確認し、条件付き分岐がそれらを無視することを保証する両方の状態で無視されるフラグ ビットを持つさまざまな条件付き分岐につながります。また、条件分岐がそれらを変更することになっていない場合は、そうでないことを確認してください。同様に、条件が条件付きフラグに触れないという分岐を引き起こさない場合... すべての条件付き分岐がその 1 つの条件でのみ動作することを確認し、条件付き分岐がそれらを無視することを保証する両方の状態で無視されるフラグ ビットを持つさまざまな条件付き分岐につながります。また、条件分岐がそれらを変更することになっていない場合は、そうでないことを確認してください。同様に、条件が条件付きフラグに触れないという分岐を引き起こさない場合...
私はランダム化を使用するのが好きですが、それはあなたが求めているよりも多くの作業になるかもしれません. 私は、命令セットのソフトウェア シミュレーターを独自に開発するのが好きです。これは使いやすく、ロジックはバッチ テストで使いやすい場合もあります。次に、命令の短いリストをランダム化し、命令とレジスタを変更し、テスト完了後のレジスタの状態とフラグビットの状態の両方で、結果の一部を手動で計算してテスターを自然にテストできます。次に、そのランダム化されたリストを長くします。ある時点で、長い命令リストを取得してロジックシミュレーターで実行し、ロジックが命令セットシミュレーターと同じレジスタ結果とフラグビットを生成するかどうかを確認します。どうして。別のランダム シーケンスを試さない場合は、別のシーケンスを試してください。
個々の命令テストに戻ると、フラグはすべてのコーナー ケース 0xFFFF + 0x0000 0xFFFF+1 を通過します。たとえば、オペランドと結果のちょうど両側と右に配置され、フラグが変化するポイントから 1 カウント離れた場所に配置されます。旗が変わり、その反対側です。たとえば、ゼロフラグを使用する論理の場合、0x0000、0xFFFF 0xFFFE 0x0001 0x0002 などの両側にある結果をテストするさまざまなデータパターンがあります。など
うまくいけば、私はあなたの質問を理解し、明白なことやあなたがこれまでに行ったことを指摘していません.