継続のためのArduinoのチューニングツールチェーン

むかしむかし、コード生成の予測可能性に非常に特定の要件があったArduinoでプロジェクトに取り組んでいたことがあり、ブラックボックスでの作業は場所によっては面倒でした。 そのため、組み立てプロセスをわずかに調整し、組み立て中にいくつかの追加手順を導入するというアイデアが生まれました。

ご存知のように、 Wiring言語は実際には本格的なC ++であり、ランタイム環境の重さのために例外のサポートが削除され、メイン関数の実装など、プログラムの構造に関連するいくつかの微妙さが隠され、開発者にはから呼び出されるセットアップおよびループ関数が与えられますメイン

これは、誰も話していない場合でも、C ++パンを使用できることを意味します。

この記事に記載されているすべては、少なくとも1.6以降のArduino環境のバージョンに適用されます。 私はすべてをWindowsで行いましたが、Linux / MacOSのアプローチは同じままで、技術的な詳細は変更されます。

それでは、始めましょう。

バージョン1.6環境では、GCCバージョン4.8コンパイラがデフォルトで使用されます。これには、デフォルトでC ++ 11のサポートが含まれていませんが、自動、可変テンプレート、およびその他の機能も必要です。 また、バージョン1.8の環境では、コンパイラーは既にバージョン4.9であり、デフォルトでC ++ 11をサポートしますが、右辺値参照、定数式、セパレーター、バイナリリテラル、およびその他の喜びを備えたC ++ 14の使用を強制することもできます。

デフォルトで含まれているよりも新しい標準のサポートを追加するには、コンパイル設定を含むArduinoインストールディレクトリのhardware\arduino\avr\platform.txtファイルを開き、 compiler.cpp.flagsパラメータを見つけて、目的の言語標準を指定します: -std=gnu++11-std=gnu++14置き換えます。 パラメータがない場合は、たとえば、行の最後に追加します。

ファイルを保存したら、スケッチの再構築を試すことができます-環境はすぐに新しい設定を取得します。

ここでは、 -Osオプションを-Ofast変更することで、よりコンパクトなコードではなく、最適化設定を変更して、より高速なコードの生成を有効にできます。

これらの設定はグローバルであるため、すべてのプロジェクトに適用できます。

次に、コンパイラーの結果をより詳細に制御することを決定し、ポストビルドイベントの類似物を追加しました。 これを行うには、 recipe.hooks.postbuild.0.patternパラメーターを同じファイルに追加します。このファイルの値には、アセンブリ後に起動されるファイルの名前とコマンドライン引数を含める必要があります。 値"{compiler.path}stat.bat" "{build.path}/{build.project_name}"を割り当てました。 そのようなファイルはまだないので、 hardware\tools\avr\bin (明らかにstat.batという名前で)作成する必要があります。

そこに次の行を書きましょう。

 "%~dp0\avr-objdump.exe" -d -C %1.elf > %1.SX "%~dp0\avr-nm.exe" %1.elf -nCS > %1.names 

最初の行は、objdumpを使用して既にコンパイルおよび最適化されたプログラムの逆コンパイルを開始し、プロジェクト名と追加の拡張子.SXを使用して出力ファイルを作成します(選択は任意ですが、Sは伝統的にアセンブラーであり、Xは何らかの変換の事実を示します)。

2行目では、nmコマンドを実行してメモリ領域のシンボル名を抽出し、ファイルに追加の拡張子.namesを付けてレポートを生成しますが、ソートはアドレスで実行されます。

ここで、アセンブリが一時ディレクトリで実行されることを追加することも必要です。それを確認するには、Arduino設定に移動し、[詳細出力を表示]-> [コンパイル]チェックボックスをオンにします。 私の場合(IDEバージョン1.8.5)は、 %TEMP%\arduino_build_[random]ようなディレクトリでした。

普通の生活で逆アセンブルされたコードを読むことは疑わしい喜びですが、誰かにとっては必要かもしれません(私はたまたま行ったことがあります)。

通常、名前のファイルの方が便利です。 ネタバレ-実験を行ったテストスケッチ:

テストスケッチ
 int counter = 1; void test(auto&& x) { static unsigned long time; long t = millis(); Serial.print(F("Counter: ")); Serial.println(counter); Serial.print(F(" At ")); Serial.print(t); Serial.print(F(" value is ")); Serial.println(x); Serial.print(F("Time between iterations: ")); Serial.println(t - time); Serial.println(); time = t; } void setup() { Serial.begin(9600); } void loop() { delay(100); test(digitalRead(A0)); } 


結果の名前のファイル全体もネタバレです。

名前ファイル全体

w serialEvent()
00000000 W __heap_end
00000000 a __tmp_reg__
00000000 a __tmp_reg__
00000000 a __tmp_reg__
00000000 a __tmp_reg__
00000000 a __tmp_reg__
00000000 a __tmp_reg__
00000000 a __tmp_reg__
00000000 a __tmp_reg__
00000000 a __tmp_reg__
00000000 W __vector_default
00000000 T __vectors
00000001 a __zero_reg__
00000001 a __zero_reg__
00000001 a __zero_reg__
00000001 a __zero_reg__
00000001 a __zero_reg__
00000001 a __zero_reg__
00000001 a __zero_reg__
00000001 a __zero_reg__
00000001 a __zero_reg__
0000003d a __SP_L__
0000003d a __SP_L__
0000003d a __SP_L__
0000003d a __SP_L__
0000003d a __SP_L__
0000003d a __SP_L__
0000003d a __SP_L__
0000003d a __SP_L__
0000003d a __SP_L__
0000003e a __SP_H__
0000003e a __SP_H__
0000003e a __SP_H__
0000003e a __SP_H__
0000003e a __SP_H__
0000003e a __SP_H__
0000003e a __SP_H__
0000003e a __SP_H__
0000003e a __SP_H__
0000003f a __SREG__
0000003f a __SREG__
0000003f a __SREG__
0000003f a __SREG__
0000003f a __SREG__
0000003f a __SREG__
0000003f a __SREG__
0000003f a __SREG__
0000003f a __SREG__
00000068 T __trampolines_end
00000068 T __trampolines_start
00000068 0000001a t test(int)::__c
00000082 0000000b t test(int)::__c
0000008d 00000005 t test(int)::__c
00000092 0000000a t test(int)::__c
0000009c 00000014 T digital_pin_to_timer_PGM
000000b0 00000014 T digital_pin_to_bit_mask_PGM
000000c4 00000014 T digital_pin_to_port_PGM
000000d8 0000000a T port_to_input_PGM
000000e2 T __ctors_start
000000e4 T __ctors_end
000000e4 T __dtors_end
000000e4 T __dtors_start
000000e4 W __init
000000f0 00000016 T __do_copy_data
00000106 00000010 T __do_clear_bss
0000010e t .do_clear_bss_loop
00000110 t .do_clear_bss_start
00000116 00000016 T __do_global_ctors
00000134 T __bad_interrupt
00000134 W __vector_1
00000134 W __vector_10
00000134 W __vector_11
00000134 W __vector_12
00000134 W __vector_13
00000134 W __vector_14
00000134 W __vector_15
00000134 W __vector_17
00000134 W __vector_2
00000134 W __vector_20
00000134 W __vector_21
00000134 W __vector_22
00000134 W __vector_23
00000134 W __vector_24
00000134 W __vector_25
00000134 W __vector_3
00000134 W __vector_4
00000134 W __vector_5
00000134 W __vector_6
00000134 W __vector_7
00000134 W __vector_8
00000134 W __vector_9
00000138 00000012 T setup
0000014a 000000d8 T loop
00000222 00000094 T __vector_16
000002b6 00000018 T millis
000002ce 00000046 T micros
00000314 00000050 T delay
00000364 00000076 T init
000003da 00000052 t turnOffPWM
0000042c 00000052 T digitalRead
0000047e 00000016 T HardwareSerial::available()
00000494 0000001c T HardwareSerial::peek()
000004b0 00000028 T HardwareSerial::read()
000004d8 000000b8 T HardwareSerial::write(unsigned char)
00000590 000000a4 T HardwareSerial::flush()
00000634 0000001c W serialEventRun()
00000650 00000042 T HardwareSerial::_tx_udr_empty_irq()
00000692 000000d0 T HardwareSerial::begin(unsigned long, unsigned char)
00000762 00000064 T __vector_18
000007c6 0000004c T __vector_19
00000812 00000014 T Serial0_available()
00000826 00000086 t _GLOBAL__sub_I___vector_18
000008ac 00000002 W initVariant
000008ae 00000028 T main
000008d6 00000058 T Print::write(unsigned char const*, unsigned int)
000008ff W __stack
0000092e 0000004a T Print::print(__FlashStringHelper const*)
00000978 00000242 T Print::print(long, int)
00000bba 00000016 T Print::println()
00000bd0 0000029a T Print::println(int, int)
00000e6a 0000013a T Print::println(unsigned long, int)
00000fa4 00000002 t __empty
00000fa4 00000002 W yield
00000fa6 00000044 T __udivmodsi4
00000fb2 t __udivmodsi4_loop
00000fcc t __udivmodsi4_ep
00000fea 00000004 T __tablejump2__
00000fee 00000008 T __tablejump__
00000ff6 T _exit
00000ff6 W exit
00000ff8 t __stop_program
00000ffa A __data_load_start
00000ffa T _etext
00001016 A __data_load_end
00800100 D __data_start
00800100 00000002 D counter
00800102 00000010 V vtable for HardwareSerial
0080011c B __bss_start
0080011c D __data_end
0080011c D _edata
0080011c 00000004 b test(int)::time
00800120 00000001 b timer0_fract
00800121 00000004 B timer0_millis
00800125 00000004 B timer0_overflow_count
00800129 0000009d B Serial
008001c6 B __bss_end
008001c6 N _end
00810000 N __eeprom_end



読み方は? 正しくしましょう。

AVRコントローラには、プログラムメモリとデータメモリの2つの独立したメモリ領域があります。 したがって、コードへのポインターとデータへのポインターは同じものではありません。 EEPROMについては言及していませんが、アドレス指定については別の会話があります。 ダンプでは、プログラムメモリはオフセット0にあり、そこから実行が開始されます。また、要素ごとに4バイトの割り込みベクトルのテーブルもあります。 x86とは異なり、各割り込みベクトルにはハンドラーのアドレスは含まれませんが、実行する必要がある命令が含まれます。 通常(他のオプションを見たことがない)-jmp、つまり、目的のアドレスへの移行。 しばらくの間、割り込みベクターに戻りますが、今のところはさらに調べます。

データメモリは、オフセット0のレジスタファイルとオフセット0x100のランダムアクセスメモリ(SRAM)のデータの2つの部分で構成されています。 メモリダンプが出力されると、オフセット0x00800000がSRAMアドレスに追加されます。これは本質的には何も意味しませんが、便利です。 EEPROMオフセットの値は0x00810000ですが、これは必要ありません。

データから始めましょう。ここではすべてが少しシンプルでわかりやすいので、コードに戻ります。 最初の列はオフセット、2番目はサイズ、次にタイプ(注意を払うまで)、行の最後が名前です。

オフセット0x00800100に移動して、エントリを確認します。

 00800100 D __data_start 00800100 00000002 D counter 00800102 00000010 V vtable for HardwareSerial 0080011c D __data_end 

.dataセクションに類似しており、初期化されたグローバル変数と静的変数、および仮想メソッドテーブルが含まれています。 これらの変数はブートストラップコードで初期化されますが、これには時間がかかります。

さらに進んでいきます(__bss_startと__data_endがランダムな順序で実行されることを気にしないでください-それらは共通のアドレスを持っています)。

 0080011c B __bss_start 0080011c 00000004 b test(int)::time 00800120 00000001 b timer0_fract 00800121 00000004 B timer0_millis 00800125 00000004 B timer0_overflow_count 00800129 0000009d B Serial 008001c6 B __bss_end 

これは、初期化されていないデータのセクションです(.bssに類似)。 0バイトで埋められているため、何も与えられません。 いくつかのヘルパー変数、timer0_で始まる名前、グローバルシリアルオブジェクト、および静的ローカル変数を次に示します。

小さな叙情的な余談:Serialオブジェクトは最初は空であり、beginメソッドが呼び出されると初期化されることに注意してください。 これにはいくつかの理由があります。 第一に、それはまったく使用されないかもしれません(そして、それはまったく作成されず、それに割り当てられるスペースもありません)、第二に、グローバルオブジェクトの初期化の順序が定義されていないこと、そして厳密に言うと、コントローラー正しく初期化されていません。

上位アドレスに、スタックが配置されます。 コントローラのメモリが2キロバイト(atmega328プロセッサに基づくボード)の場合、最後のアドレスは0x008008FFになります。 このアドレスからスタックが始まり、アドレスの減少に向かって成長します。 障壁はありません。原則として、スタックは変数をクロールし、それらを破壊します。 または、データがスタックを破壊する可能性があります。 この場合、良いことは何も起こりません。 この未定義の動作を呼び出すことができますが、メモリにスタック用の十分なスペースを常に残しておくことをお勧めします。 どれだけ言いにくいか。 これは、すべての呼び出しのローカル変数とスタックフレームに加えて、すべてのネストされた呼び出しで最も重い割り込みハンドラーに十分でした。 正直に言って、スタックの使用を診断する方法について、多少なりとも正直な決定を見つけることはできませんでした。

コードに戻りましょう。 コードがそこに保存されていると言ったとき、私は少し不誠実でした。 実際、読み取り専用データはそこに格納できますが、それらはLPMプロセッサーからの特別な命令によってそこから抽出されます。 そのため、初期化に時間が無駄にならないため、定数データをそこに配置し、何のためにも配置することはできません。 コード内のマクロF(...)に注意してください。 プログラムメモリに配置された行を宣言するだけで、少し魔法をかけます。 魔法の詳細については触れませんが、記憶の中からそれらを探します。 このようなマクロはテスト関数に移動し、ダンプでは次のように表示されます

 00000068 0000001a t test(int)::__c 00000082 0000000b t test(int)::__c 0000008d 00000005 t test(int)::__c 00000092 0000000a t test(int)::__c 

彼らは同じ名前を持っているという事実にもかかわらず、それらは異なるアドレスに位置しています。 マクロF(...)は中括弧でスコープを作成し、変数(より正確には定数)は互いに干渉しないためです。 逆アセンブルされたダンプを見ると、これらはプログラムメモリ内の行のアドレスになります。

そして最後に、約束された中断。 ライブラリは、周辺機器の動作をサポートするために、タイマー、通信インターフェイスなどのコントローラーリソースを使用します 割り込みハンドラを登録し、変数をメモリに保存し、定数をプログラムメモリに保存します。 空のスケッチをコンパイルすると、メモリダンプは次のようになります。

空のスケッチメモリダンプ
w serialEventRun()
00000000 W __heap_end
00000000 a __tmp_reg__
00000000 a __tmp_reg__
00000000 a __tmp_reg__
00000000 a __tmp_reg__
00000000 W __vector_default
00000000 T __vectors
00000001 a __zero_reg__
00000001 a __zero_reg__
00000001 a __zero_reg__
00000001 a __zero_reg__
0000003d a __SP_L__
0000003d a __SP_L__
0000003d a __SP_L__
0000003d a __SP_L__
0000003e a __SP_H__
0000003e a __SP_H__
0000003e a __SP_H__
0000003e a __SP_H__
0000003f a __SREG__
0000003f a __SREG__
0000003f a __SREG__
0000003f a __SREG__
00000068 T __ctors_end
00000068 T __ctors_start
00000068 T __dtors_end
00000068 T __dtors_start
00000068 W __init
00000068 T __trampolines_end
00000068 T __trampolines_start
00000074 00000010 T __do_clear_bss
0000007c t .do_clear_bss_loop
0000007e t .do_clear_bss_start
0000008c T __bad_interrupt
0000008c W __vector_1
0000008c W __vector_10
0000008c W __vector_11
0000008c W __vector_12
0000008c W __vector_13
0000008c W __vector_14
0000008c W __vector_15
0000008c W __vector_17
0000008c W __vector_18
0000008c W __vector_19
0000008c W __vector_2
0000008c W __vector_20
0000008c W __vector_21
0000008c W __vector_22
0000008c W __vector_23
0000008c W __vector_24
0000008c W __vector_25
0000008c W __vector_3
0000008c W __vector_4
0000008c W __vector_5
0000008c W __vector_6
0000008c W __vector_7
0000008c W __vector_8
0000008c W __vector_9
00000090 00000002 T setup
00000092 00000002 T loop
00000094 00000002 W initVariant
00000096 00000028 T main
000000be 00000094 T __vector_16
00000152 00000076 T init
000001c8 T _exit
000001c8 W exit
000001ca t __stop_program
000001cc A __data_load_end
000001cc a __data_load_start
000001cc T _etext
000008ff W __stack
00800100 B __bss_start
00800100 D _edata
00800100 00000001 b timer0_fract
00800101 00000004 B timer0_millis
00800105 00000004 B timer0_overflow_count
00800109 B __bss_end
00800109 N _end
00810000 N __eeprom_end

たくさんありませんか?

そして、ここにコードがあります:

逆アセンブルされたコード
 /empty.cpp.elf: file format elf32-avr Disassembly of section .text: 00000000 <__vectors>: 0: 0c 94 34 00 jmp 0x68 ; 0x68 <__ctors_end> 4: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 8: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> c: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 10: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 14: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 18: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 1c: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 20: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 24: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 28: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 2c: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 30: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 34: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 38: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 3c: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 40: 0c 94 5f 00 jmp 0xbe ; 0xbe <__vector_16> 44: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 48: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 4c: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 50: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 54: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 58: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 5c: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 60: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 64: 0c 94 46 00 jmp 0x8c ; 0x8c <__bad_interrupt> 00000068 <__ctors_end>: 68: 11 24 eor r1, r1 6a: 1f be out 0x3f, r1 ; 63 6c: cf ef ldi r28, 0xFF ; 255 6e: d8 e0 ldi r29, 0x08 ; 8 70: de bf out 0x3e, r29 ; 62 72: cd bf out 0x3d, r28 ; 61 00000074 <__do_clear_bss>: 74: 21 e0 ldi r18, 0x01 ; 1 76: a0 e0 ldi r26, 0x00 ; 0 78: b1 e0 ldi r27, 0x01 ; 1 7a: 01 c0 rjmp .+2 ; 0x7e <.do_clear_bss_start> 0000007c <.do_clear_bss_loop>: 7c: 1d 92 st X+, r1 0000007e <.do_clear_bss_start>: 7e: a9 30 cpi r26, 0x09 ; 9 80: b2 07 cpc r27, r18 82: e1 f7 brne .-8 ; 0x7c <.do_clear_bss_loop> 84: 0e 94 4b 00 call 0x96 ; 0x96 <main> 88: 0c 94 e4 00 jmp 0x1c8 ; 0x1c8 <_exit> 0000008c <__bad_interrupt>: 8c: 0c 94 00 00 jmp 0 ; 0x0 <__vectors> 00000090 <setup>: 90: 08 95 ret 00000092 <loop>: 92: 08 95 ret 00000094 <initVariant>: 94: 08 95 ret 00000096 <main>: 96: 0e 94 a9 00 call 0x152 ; 0x152 <init> 9a: 0e 94 4a 00 call 0x94 ; 0x94 <initVariant> 9e: 0e 94 48 00 call 0x90 ; 0x90 <setup> a2: 80 e0 ldi r24, 0x00 ; 0 a4: 90 e0 ldi r25, 0x00 ; 0 a6: 89 2b or r24, r25 a8: 29 f0 breq .+10 ; 0xb4 <main+0x1e> aa: 0e 94 49 00 call 0x92 ; 0x92 <loop> ae: 0e 94 00 00 call 0 ; 0x0 <__vectors> b2: fb cf rjmp .-10 ; 0xaa <main+0x14> b4: 0e 94 49 00 call 0x92 ; 0x92 <loop> b8: 0e 94 49 00 call 0x92 ; 0x92 <loop> bc: fb cf rjmp .-10 ; 0xb4 <main+0x1e> 000000be <__vector_16>: be: 1f 92 push r1 c0: 0f 92 push r0 c2: 0f b6 in r0, 0x3f ; 63 c4: 0f 92 push r0 c6: 11 24 eor r1, r1 c8: 2f 93 push r18 ca: 3f 93 push r19 cc: 8f 93 push r24 ce: 9f 93 push r25 d0: af 93 push r26 d2: bf 93 push r27 d4: 80 91 01 01 lds r24, 0x0101 d8: 90 91 02 01 lds r25, 0x0102 dc: a0 91 03 01 lds r26, 0x0103 e0: b0 91 04 01 lds r27, 0x0104 e4: 30 91 00 01 lds r19, 0x0100 e8: 23 e0 ldi r18, 0x03 ; 3 ea: 23 0f add r18, r19 ec: 2d 37 cpi r18, 0x7D ; 125 ee: 20 f4 brcc .+8 ; 0xf8 <__vector_16+0x3a> f0: 01 96 adiw r24, 0x01 ; 1 f2: a1 1d adc r26, r1 f4: b1 1d adc r27, r1 f6: 05 c0 rjmp .+10 ; 0x102 <__vector_16+0x44> f8: 26 e8 ldi r18, 0x86 ; 134 fa: 23 0f add r18, r19 fc: 02 96 adiw r24, 0x02 ; 2 fe: a1 1d adc r26, r1 100: b1 1d adc r27, r1 102: 20 93 00 01 sts 0x0100, r18 106: 80 93 01 01 sts 0x0101, r24 10a: 90 93 02 01 sts 0x0102, r25 10e: a0 93 03 01 sts 0x0103, r26 112: b0 93 04 01 sts 0x0104, r27 116: 80 91 05 01 lds r24, 0x0105 11a: 90 91 06 01 lds r25, 0x0106 11e: a0 91 07 01 lds r26, 0x0107 122: b0 91 08 01 lds r27, 0x0108 126: 01 96 adiw r24, 0x01 ; 1 128: a1 1d adc r26, r1 12a: b1 1d adc r27, r1 12c: 80 93 05 01 sts 0x0105, r24 130: 90 93 06 01 sts 0x0106, r25 134: a0 93 07 01 sts 0x0107, r26 138: b0 93 08 01 sts 0x0108, r27 13c: bf 91 pop r27 13e: af 91 pop r26 140: 9f 91 pop r25 142: 8f 91 pop r24 144: 3f 91 pop r19 146: 2f 91 pop r18 148: 0f 90 pop r0 14a: 0f be out 0x3f, r0 ; 63 14c: 0f 90 pop r0 14e: 1f 90 pop r1 150: 18 95 reti 00000152 <init>: 152: 78 94 sei 154: 84 b5 in r24, 0x24 ; 36 156: 82 60 ori r24, 0x02 ; 2 158: 84 bd out 0x24, r24 ; 36 15a: 84 b5 in r24, 0x24 ; 36 15c: 81 60 ori r24, 0x01 ; 1 15e: 84 bd out 0x24, r24 ; 36 160: 85 b5 in r24, 0x25 ; 37 162: 82 60 ori r24, 0x02 ; 2 164: 85 bd out 0x25, r24 ; 37 166: 85 b5 in r24, 0x25 ; 37 168: 81 60 ori r24, 0x01 ; 1 16a: 85 bd out 0x25, r24 ; 37 16c: ee e6 ldi r30, 0x6E ; 110 16e: f0 e0 ldi r31, 0x00 ; 0 170: 80 81 ld r24, Z 172: 81 60 ori r24, 0x01 ; 1 174: 80 83 st Z, r24 176: e1 e8 ldi r30, 0x81 ; 129 178: f0 e0 ldi r31, 0x00 ; 0 17a: 10 82 st Z, r1 17c: 80 81 ld r24, Z 17e: 82 60 ori r24, 0x02 ; 2 180: 80 83 st Z, r24 182: 80 81 ld r24, Z 184: 81 60 ori r24, 0x01 ; 1 186: 80 83 st Z, r24 188: e0 e8 ldi r30, 0x80 ; 128 18a: f0 e0 ldi r31, 0x00 ; 0 18c: 80 81 ld r24, Z 18e: 81 60 ori r24, 0x01 ; 1 190: 80 83 st Z, r24 192: e1 eb ldi r30, 0xB1 ; 177 194: f0 e0 ldi r31, 0x00 ; 0 196: 80 81 ld r24, Z 198: 84 60 ori r24, 0x04 ; 4 19a: 80 83 st Z, r24 19c: e0 eb ldi r30, 0xB0 ; 176 19e: f0 e0 ldi r31, 0x00 ; 0 1a0: 80 81 ld r24, Z 1a2: 81 60 ori r24, 0x01 ; 1 1a4: 80 83 st Z, r24 1a6: ea e7 ldi r30, 0x7A ; 122 1a8: f0 e0 ldi r31, 0x00 ; 0 1aa: 80 81 ld r24, Z 1ac: 84 60 ori r24, 0x04 ; 4 1ae: 80 83 st Z, r24 1b0: 80 81 ld r24, Z 1b2: 82 60 ori r24, 0x02 ; 2 1b4: 80 83 st Z, r24 1b6: 80 81 ld r24, Z 1b8: 81 60 ori r24, 0x01 ; 1 1ba: 80 83 st Z, r24 1bc: 80 81 ld r24, Z 1be: 80 68 ori r24, 0x80 ; 128 1c0: 80 83 st Z, r24 1c2: 10 92 c1 00 sts 0x00C1, r1 1c6: 08 95 ret 000001c8 <_exit>: 1c8: f8 94 cli 000001ca <__stop_program>: 1ca: ff cf rjmp .-2 ; 0x1ca <__stop_program> 


タイマー割り込み、このタイマーを処理するための9バイト、および一定量のインフラストラクチャコードが含まれます。

今日は、おそらく十分でしょう。 誰かが役に立つといいな。

Source: https://habr.com/ru/post/J346202/


All Articles