4

6502 アセンブリの制御フローを理解しようとしています。

次のコードがあるとします。

    ControlFlow:
      lda mem
      cmp #1
      bne .sub_one

      cmp #2
      bne .sub_two

      .sub_one:
        ; sub routine one goes here
        jmp .done ; <-------------- without this jmp, .sub_two will execute

      .sub_two:
       ; sub routine two goes here

      .done:

      rts

個人的には、switch ステートメントやその他の制御フロー構造が好きです。上記の JMP は私にも関係があります。この種のスパゲッティ コードを使用せずに、複数のケースを処理するためのより良い方法があるようです。

4

7 に答える 7

5

ケースの数が十分に多い場合は、ジャンプテーブルが役立ちます。左側には、ラベルにジャンプするためのテンプレート(テストされていない)があり、正しいアドレスをスタックにプッシュして返します。右側には、jsrベースのルーチンとの差分_out:があり、各サブルーチンから戻った後もラベルで続行されます。キャリーロジックは6502で反転されます。つまり、(Acc> = Imm)の場合にキャリーが設定されます。

; goto  label[n]   vs.         call label[n]

lda variable
cmp #MAX_PLUS_ONE                          
bcs _out
tax
lda table_hi, X
pha                vs.         sta jsrcmd+2
lda table_lo, X
pha                vs.         sta jsrcmd+1
rts                vs. jsrcmd: jsr 1000        ; self modify

_out:  
于 2013-01-20T09:20:38.627 に答える
4

実際にはこれ以上の方法はありませんが、FlowControl をサブルーチンとして呼び出して RTS で返すなどの改善があるかもしれません。

これが主な流れです。

  jsr ControlFlow
  ; main routine continues here

これがサブルーチンです。

ControlFlow:
  lda mem
  cmp #1
  bne .sub_one
  cmp #2
  bne .sub_two
  cmp #3
  bne .sub_three
    ; case else here
  rts

  .sub_one:
    ; sub routine one goes here
  rts

  .sub_two:
   ; sub routine two goes here
  rts

  .sub_three:
   ; sub routine three goes here
  rts

サブルーチンが長すぎる場合は、前述のように JMP を使用する必要があります。

.jump_to_sub_one
  jmp .sub_one
.jump_to_sub_two
  jmp .sub_two
.jump_to_sub_three
  jmp .sub_three

ControlFlow:
  lda mem
  cmp #1
  bne .jump_to_sub_one
  cmp #2
  bne .jump_to_sub_two
  cmp #3
  bne .jump_to_sub_three
    ; case else here
  rts

  .sub_one:
    ; sub routine one goes here
  rts

  .sub_two:
   ; sub routine two goes here
  rts

  .sub_three:
   ; sub routine three goes here
  rts

それが行われる方法であり、残念ながら、これ以上の方法はありません。これは、すべてではないにしても、多くのアセンブリ言語に当てはまります。

于 2013-01-19T09:29:14.430 に答える
3

6502 は、プログラム フローを制御するために次の機能を提供します。つまり、PC レジスタを変更します。

  • JMPアブソリュート
  • JMP間接
  • Bxx 相対命令
  • 後の RTS を使用した JSR アブソリュート
  • .P後の RTI を使用した BRK またはその他の IRQ (または、スタックをプルオフする場合は RTS )
  • 2 つの値をスタックにプッシュしてから RTS/RTI をプッシュする
  • ハードウェア リセットにより、リセット ベクターを介したジャンプが発生する

それでおしまい。もっと複雑なものが必要な場合は、上記の 1 つまたは複数を使用して作成する必要があります。

switch ステートメントを実装する 1 つの方法は、switch ステートメントに含まれるすべてのルーチンへのポインターのテーブルを最初に作成することです。ルーチンの下位バイト、次に上位バイトに従ってそれらを分割します。

switchtab_lo .db >routine1, >routine2, >routine3

switchtab_hi .db <routine1, <routine2, <routine3

( > が下位バイトまたは上位バイトを意味し、異なるアセンブラが異なる構文を持っている可能性があるかどうかは思い出せません)

次に、切り替えたい値が .X にあると仮定します。これvectorは、ページの最後から始まらない 2 バイトであり (JMP の間接的なバグを回避するため)、有効な値であることを確認しました。 :

lda switchtab_lo,X
sta vector
lda switchtab_hi,X
sta vector+1
jmp (vector)

切り替える必要があるたびにこれを行うのは面倒ですが、それが高水準言語が発明された理由です。

于 2013-08-18T14:27:06.133 に答える
2
        lda mem
        asl
        sta jump+1
jump    jmp (vector)

;should be page aligned
vector
        !word func1, func2, func3, func4

ベクトルのリストが整列されていない場合は、インデックス*2 をベクトル アドレス全体に追加する必要があります。速度は遅くなりますが、メモリ効率が向上します。

他のオプションは次のとおりです。

         lda mem
         asl
         clc
         adc mem        ;we assume it does not overflow, so carry stays cleared
         sta branch+1   ;mem * 3
branch   bcc *
         jmp func1
         jmp func2
         jmp func3
         jmp ...
于 2015-10-21T06:58:36.533 に答える
1

CMOS 6502 (つまり、65c02) にはJMP(abs,X)アドレッシング モードもあるため、A で入力を取得し、ASL A で左に 1 ビット シフトします (テーブル内の各アドレスは 2 つの場所を取るため)。それを X に転送し、JMP(Addr_Table,X) を実行します。はるかに簡単です。これは、CMOS バージョンで行われた多くのオペコードの追加の 1 つです。(CMOS バージョンでは、NMOS バージョンのすべてのバグも修正されています)。

于 2013-11-22T22:11:46.003 に答える
0

http://wilsonminesco.com/StructureMacros/index.htmlに、マクロを使用して 6502 アセンブリでプログラム構造を作成する方法に関する記事があります。私はPICでもそれを行いました.リンクは両方のソースコードにあります. 私が取り組んでいるプロジェクトを終了すると、さらに追加が行われます。

OP は IF...ELSE...END_IF に最適な状況です。より多くのケースが必要な場合、数値が連続していればジャンプ テーブルがうまく機能し、テーブルの外側から間接的にジャンプしてクラッシュするのを避けるために制限をテストする必要はありません。それ以外の場合は、CASE ステートメントがうまく機能します。 http://forum.6502.org/viewtopic.php?f=2&t=2311&start=15はそのような議論の 2 ページ目で、個々のケース、数値の範囲、または分散をテストする方法を示しています。すべて同じ CASE ステートメント内の数値のすべて。RANGE_OF と SET_OF を 6502 アセンブリ マクロとしてまだ作成していません。それらは私がForでしか持っていない2つです。

もちろん、これらのマクロの目的は、何をしているかをより明確にし、アセンブリ コードを一般的に特徴付ける大量のラベルとジャンプを取り除くことによって、コードをより適切に制御することです。マクロを使用すると、アセンブラーによって配置されたコードのすべての詳細を完全に制御できますが、内部の詳細を調べ続ける必要はありません。ほとんどの場合、使用されるプログラム メモリまたは実行速度のペナルティはまったくありません。高水準言語の多くの利点を備えたアセンブリのパフォーマンスが得られます。コードの開発が速くなり、バグがなくなり、保守が容易になります。つまり、機能を追加したり何かを変更したりすることにしたときに、後で戻って何をしたかを把握するのが簡単になります。

于 2013-03-04T04:10:17.803 に答える
0

6502 でこれを行う方法はわかりませんが、switches はしばしばjump tableにコンパイルされます。

于 2013-01-19T04:15:45.280 に答える