digitalWrite(pin, state) の引数はほとんど固定で使うことが多い (と思いますがどうでしょうか? http://lowreal.net/2015/12/14/1 こういうケースでは常に固定ですね) が、digitalWrite は実装上、実行時にいちいちテーブルを使って、ピン番号からどのポートのどのビットかをひいている。たいへん無駄である。
そして、digitalWrite() は1度の1つのビットしか設定できないという制約がある。これは大変こまる場合がある (同時に複数のビットを設定して出力を変化させようとしても、タイムラグができてしまう)
ということで、これらを解決できないかと思った結果 C++ のテンプレートメタプログラミングに手を出すことになった
前提
Arduino が使っている 8bit AVR では PORTB, PORTC, PORTD などと最大8bitのレジスタがあり、これら単位では同時に操作が可能になっている。
Arduino ではこれらのポート単位を隠蔽し、ピン番号という一連の番号によって区別するように抽象化されている。具体的には 0〜7 が PD, 8〜14 が PB というような感じ (standard なArduino の場合)
仕様
- digitalWrite() とインターフェイス互換であること (静的であること以外)
- 複数ビットを同時に操作できること
- 指定したピン番号同士のポートが同一でない場合エラーとすること
// オリジナル。0ピンをLOWにする digitalWrite(0, LOW); // 作ったもの。0ピンをLOW, 1ピンをHIGH... とする (同時に) WRITE_MULTI( 0, LOW, 1, HIGH, 2, LOW, 3, HIGH );
コード
Gist
//#!ano build -f="-std=c++11 -Os" && /Applications/Arduino.app/Contents/Java/hardware/tools/avr/bin/avr-objdump -d .build_ano/uno/firmware.elf ;: | |
#include <Arduino.h> | |
// ARDUINO_MAIN で ifdef されているので外からみえない | |
constexpr uint8_t PB = 2; | |
constexpr uint8_t PC = 3; | |
constexpr uint8_t PD = 4; | |
// template version of Arduino builtin functions | |
constexpr uint16_t port_to_mode[] = { | |
NOT_A_PORT, | |
NOT_A_PORT, | |
(uint16_t) &DDRB, | |
(uint16_t) &DDRC, | |
(uint16_t) &DDRD, | |
}; | |
constexpr uint16_t port_to_output[] = { | |
NOT_A_PORT, | |
NOT_A_PORT, | |
(uint16_t) &PORTB, | |
(uint16_t) &PORTC, | |
(uint16_t) &PORTD, | |
}; | |
constexpr uint16_t port_to_input[] = { | |
NOT_A_PORT, | |
NOT_A_PORT, | |
(uint16_t) &PINB, | |
(uint16_t) &PINC, | |
(uint16_t) &PIND, | |
}; | |
constexpr uint8_t digital_pin_to_port[] = { | |
PD, /* 0 */ | |
PD, | |
PD, | |
PD, | |
PD, | |
PD, | |
PD, | |
PD, | |
PB, /* 8 */ | |
PB, | |
PB, | |
PB, | |
PB, | |
PB, | |
PC, /* 14 */ | |
PC, | |
PC, | |
PC, | |
PC, | |
PC, | |
}; | |
constexpr uint8_t digital_pin_to_bit_mask[] = { | |
_BV(0), /* 0, port D */ | |
_BV(1), | |
_BV(2), | |
_BV(3), | |
_BV(4), | |
_BV(5), | |
_BV(6), | |
_BV(7), | |
_BV(0), /* 8, port B */ | |
_BV(1), | |
_BV(2), | |
_BV(3), | |
_BV(4), | |
_BV(5), | |
_BV(0), /* 14, port C */ | |
_BV(1), | |
_BV(2), | |
_BV(3), | |
_BV(4), | |
_BV(5), | |
}; | |
template<uint8_t port> | |
constexpr volatile uint8_t* portModeRegisterX() { | |
static_assert(port < sizeof(port_to_mode), "invalid port number"); | |
static_assert(port_to_mode[port] != NOT_A_PORT, "invalid port number"); | |
return (volatile uint8_t*)port_to_mode[port]; | |
} | |
template<uint8_t port> | |
constexpr volatile uint8_t* portOutputRegisterX() { | |
static_assert(port < sizeof(port_to_output), "invalid port number"); | |
static_assert(port_to_output[port] != NOT_A_PORT, "invalid port number"); | |
return (volatile uint8_t*)port_to_output[port]; | |
} | |
template<uint8_t port> | |
constexpr volatile uint8_t* portInputRegisterX() { | |
static_assert(port < sizeof(port_to_input), "invalid port number"); | |
static_assert(port_to_input[port] != NOT_A_PORT, "invalid port number"); | |
return (volatile uint8_t*)port_to_input[port]; | |
} | |
template <uint16_t pin> | |
constexpr uint8_t digitalPinToBitMaskX() { | |
static_assert(pin < sizeof(digital_pin_to_bit_mask), "invalid pin number"); | |
return digital_pin_to_bit_mask[pin]; | |
}; | |
template <uint16_t pin> | |
constexpr uint8_t digitalPinToPortX() { | |
static_assert(pin < sizeof(digital_pin_to_port), "invalid pin number"); | |
return digital_pin_to_port[pin]; | |
}; | |
// multiple bit set function with cheking port consistency | |
template<uint8_t port, uint8_t mask, uint8_t vals> | |
constexpr void digitalWriteMulti_() { | |
volatile uint8_t *out = portOutputRegisterX<port>(); | |
*out = (*out & ~mask) | vals; | |
} | |
template<uint8_t port, uint8_t mask, uint8_t vals, uint16_t pin, uint8_t val, uint16_t... Rest> | |
constexpr void digitalWriteMulti_() { | |
static_assert(digitalPinToPortX<pin>() == port, "all port must be same"); | |
constexpr uint8_t bit = digitalPinToBitMaskX<pin>(); | |
digitalWriteMulti_< | |
port, | |
mask | bit, | |
vals | (val ? bit : 0), | |
Rest... | |
>(); | |
} | |
template<uint16_t pin, uint8_t val, uint16_t... Rest> | |
constexpr void digitalWriteMulti() { | |
constexpr uint8_t port = digitalPinToPortX<pin>(); | |
return digitalWriteMulti_< | |
port, | |
0, | |
0, | |
pin, | |
val, | |
Rest... | |
>(); | |
} | |
// hide template magic from surface | |
#define WRITE_MULTI(...) digitalWriteMulti<__VA_ARGS__>() | |
void setup() { | |
PORTD = (PORTD & 0b11110000) | (0b1010); | |
asm volatile ("nop"); // marker | |
// same as above | |
WRITE_MULTI( | |
0, LOW, | |
1, HIGH, | |
2, LOW, | |
3, HIGH | |
); | |
asm volatile ("nop"); | |
// another port | |
WRITE_MULTI( | |
8, LOW, | |
9, HIGH, | |
10, LOW, | |
11, HIGH | |
); | |
asm volatile ("nop"); | |
/** following is invalid | |
* static_assert(digitalPinToPortX<pin>() == port, "all port must be same"); | |
* pin=0 -> PORTB, pin=8 -> PORTC error | |
digitalWriteMulti< | |
0, LOW, | |
1, HIGH, | |
2, LOW, | |
8, HIGH | |
>(); | |
*/ | |
asm volatile ("nop"); | |
/** builtin dynamic method | |
* this is very slow | |
*/ | |
digitalWrite(0, LOW); | |
} | |
void loop() { | |
} |
.build_ano/uno/firmware.elf: file format elf32-avr | |
Disassembly of section .text: | |
00000000 <__vectors>: | |
0: 0c 94 61 00 jmp 0xc2 ; 0xc2 <__ctors_end> | |
4: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
8: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
c: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
10: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
14: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
18: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
1c: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
20: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
24: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
28: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
2c: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
30: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
34: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
38: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
3c: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
40: 0c 94 71 01 jmp 0x2e2 ; 0x2e2 <__vector_16> | |
44: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
48: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
4c: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
50: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
54: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
58: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
5c: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
60: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
64: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
00000068 <__trampolines_end>: | |
68: 00 00 nop | |
6a: 00 08 sbc r0, r0 | |
6c: 00 02 muls r16, r16 | |
6e: 01 00 .word 0x0001 ; ???? | |
70: 00 03 mulsu r16, r16 | |
72: 04 07 cpc r16, r20 | |
... | |
0000007c <digital_pin_to_bit_mask_PGM>: | |
7c: 01 02 04 08 10 20 40 80 01 02 04 08 10 20 01 02 ..... @...... .. | |
8c: 04 08 10 20 ... | |
00000090 <digital_pin_to_port_PGM>: | |
90: 04 04 04 04 04 04 04 04 02 02 02 02 02 02 03 03 ................ | |
a0: 03 03 03 03 .... | |
000000a4 <port_to_input_PGM>: | |
a4: 00 00 00 00 23 00 26 00 29 00 ....#.&.). | |
000000ae <port_to_output_PGM>: | |
ae: 00 00 00 00 25 00 28 00 2b 00 ....%.(.+. | |
000000b8 <port_to_mode_PGM>: | |
b8: 00 00 00 00 24 00 27 00 2a 00 ....$.'.*. | |
000000c2 <__ctors_end>: | |
c2: 11 24 eor r1, r1 | |
c4: 1f be out 0x3f, r1 ; 63 | |
c6: cf ef ldi r28, 0xFF ; 255 | |
c8: d8 e0 ldi r29, 0x08 ; 8 | |
ca: de bf out 0x3e, r29 ; 62 | |
cc: cd bf out 0x3d, r28 ; 61 | |
000000ce <__do_clear_bss>: | |
ce: 21 e0 ldi r18, 0x01 ; 1 | |
d0: a0 e0 ldi r26, 0x00 ; 0 | |
d2: b1 e0 ldi r27, 0x01 ; 1 | |
d4: 01 c0 rjmp .+2 ; 0xd8 <.do_clear_bss_start> | |
000000d6 <.do_clear_bss_loop>: | |
d6: 1d 92 st X+, r1 | |
000000d8 <.do_clear_bss_start>: | |
d8: a9 30 cpi r26, 0x09 ; 9 | |
da: b2 07 cpc r27, r18 | |
dc: e1 f7 brne .-8 ; 0xd6 <.do_clear_bss_loop> | |
de: 0e 94 b8 02 call 0x570 ; 0x570 <main> | |
e2: 0c 94 cc 02 jmp 0x598 ; 0x598 <_exit> | |
000000e6 <__bad_interrupt>: | |
e6: 0c 94 00 00 jmp 0 ; 0x0 <__vectors> | |
000000ea <setup>: | |
ea: 8b b1 in r24, 0x0b ; 11 | |
ec: 80 7f andi r24, 0xF0 ; 240 | |
ee: 8a 60 ori r24, 0x0A ; 10 | |
f0: 8b b9 out 0x0b, r24 ; 11 | |
f2: 00 00 nop | |
f4: 8b b1 in r24, 0x0b ; 11 | |
f6: 80 7f andi r24, 0xF0 ; 240 | |
f8: 8a 60 ori r24, 0x0A ; 10 | |
fa: 8b b9 out 0x0b, r24 ; 11 | |
fc: 00 00 nop | |
fe: 85 b1 in r24, 0x05 ; 5 | |
100: 80 7f andi r24, 0xF0 ; 240 | |
102: 8a 60 ori r24, 0x0A ; 10 | |
104: 85 b9 out 0x05, r24 ; 5 | |
106: 00 00 nop | |
108: 00 00 nop | |
10a: 60 e0 ldi r22, 0x00 ; 0 | |
10c: 80 e0 ldi r24, 0x00 ; 0 | |
10e: 0c 94 c8 00 jmp 0x190 ; 0x190 <digitalWrite> | |
00000112 <loop>: | |
112: 08 95 ret | |
00000114 <pinMode>: | |
114: cf 93 push r28 | |
116: df 93 push r29 | |
118: 90 e0 ldi r25, 0x00 ; 0 | |
11a: fc 01 movw r30, r24 | |
11c: e4 58 subi r30, 0x84 ; 132 | |
11e: ff 4f sbci r31, 0xFF ; 255 | |
120: 24 91 lpm r18, Z | |
122: fc 01 movw r30, r24 | |
124: e0 57 subi r30, 0x70 ; 112 | |
126: ff 4f sbci r31, 0xFF ; 255 | |
128: 84 91 lpm r24, Z | |
12a: 88 23 and r24, r24 | |
12c: b9 f0 breq .+46 ; 0x15c <pinMode+0x48> | |
12e: 90 e0 ldi r25, 0x00 ; 0 | |
130: 88 0f add r24, r24 | |
132: 99 1f adc r25, r25 | |
134: fc 01 movw r30, r24 | |
136: e8 54 subi r30, 0x48 ; 72 | |
138: ff 4f sbci r31, 0xFF ; 255 | |
13a: a5 91 lpm r26, Z+ | |
13c: b4 91 lpm r27, Z | |
13e: 82 55 subi r24, 0x52 ; 82 | |
140: 9f 4f sbci r25, 0xFF ; 255 | |
142: fc 01 movw r30, r24 | |
144: c5 91 lpm r28, Z+ | |
146: d4 91 lpm r29, Z | |
148: 9f b7 in r25, 0x3f ; 63 | |
14a: 66 23 and r22, r22 | |
14c: 51 f0 breq .+20 ; 0x162 <pinMode+0x4e> | |
14e: 62 30 cpi r22, 0x02 ; 2 | |
150: a1 f0 breq .+40 ; 0x17a <pinMode+0x66> | |
152: f8 94 cli | |
154: 8c 91 ld r24, X | |
156: 82 2b or r24, r18 | |
158: 8c 93 st X, r24 | |
15a: 9f bf out 0x3f, r25 ; 63 | |
15c: df 91 pop r29 | |
15e: cf 91 pop r28 | |
160: 08 95 ret | |
162: f8 94 cli | |
164: 8c 91 ld r24, X | |
166: 20 95 com r18 | |
168: 82 23 and r24, r18 | |
16a: 8c 93 st X, r24 | |
16c: 88 81 ld r24, Y | |
16e: 82 23 and r24, r18 | |
170: 88 83 st Y, r24 | |
172: 9f bf out 0x3f, r25 ; 63 | |
174: df 91 pop r29 | |
176: cf 91 pop r28 | |
178: 08 95 ret | |
17a: f8 94 cli | |
17c: 8c 91 ld r24, X | |
17e: 32 2f mov r19, r18 | |
180: 30 95 com r19 | |
182: 83 23 and r24, r19 | |
184: 8c 93 st X, r24 | |
186: 88 81 ld r24, Y | |
188: 82 2b or r24, r18 | |
18a: 88 83 st Y, r24 | |
18c: 9f bf out 0x3f, r25 ; 63 | |
18e: e6 cf rjmp .-52 ; 0x15c <pinMode+0x48> | |
00000190 <digitalWrite>: | |
190: 90 e0 ldi r25, 0x00 ; 0 | |
192: fc 01 movw r30, r24 | |
194: e8 59 subi r30, 0x98 ; 152 | |
196: ff 4f sbci r31, 0xFF ; 255 | |
198: 24 91 lpm r18, Z | |
19a: fc 01 movw r30, r24 | |
19c: e4 58 subi r30, 0x84 ; 132 | |
19e: ff 4f sbci r31, 0xFF ; 255 | |
1a0: 34 91 lpm r19, Z | |
1a2: fc 01 movw r30, r24 | |
1a4: e0 57 subi r30, 0x70 ; 112 | |
1a6: ff 4f sbci r31, 0xFF ; 255 | |
1a8: 84 91 lpm r24, Z | |
1aa: 88 23 and r24, r24 | |
1ac: 99 f0 breq .+38 ; 0x1d4 <digitalWrite+0x44> | |
1ae: 21 11 cpse r18, r1 | |
1b0: 16 c0 rjmp .+44 ; 0x1de <digitalWrite+0x4e> | |
1b2: e8 2f mov r30, r24 | |
1b4: f0 e0 ldi r31, 0x00 ; 0 | |
1b6: ee 0f add r30, r30 | |
1b8: ff 1f adc r31, r31 | |
1ba: e2 55 subi r30, 0x52 ; 82 | |
1bc: ff 4f sbci r31, 0xFF ; 255 | |
1be: a5 91 lpm r26, Z+ | |
1c0: b4 91 lpm r27, Z | |
1c2: 8f b7 in r24, 0x3f ; 63 | |
1c4: f8 94 cli | |
1c6: 9c 91 ld r25, X | |
1c8: 61 11 cpse r22, r1 | |
1ca: 05 c0 rjmp .+10 ; 0x1d6 <digitalWrite+0x46> | |
1cc: 30 95 com r19 | |
1ce: 93 23 and r25, r19 | |
1d0: 9c 93 st X, r25 | |
1d2: 8f bf out 0x3f, r24 ; 63 | |
1d4: 08 95 ret | |
1d6: 93 2b or r25, r19 | |
1d8: 9c 93 st X, r25 | |
1da: 8f bf out 0x3f, r24 ; 63 | |
1dc: fb cf rjmp .-10 ; 0x1d4 <digitalWrite+0x44> | |
1de: 23 30 cpi r18, 0x03 ; 3 | |
1e0: 29 f1 breq .+74 ; 0x22c <digitalWrite+0x9c> | |
1e2: 60 f0 brcs .+24 ; 0x1fc <digitalWrite+0x6c> | |
1e4: 27 30 cpi r18, 0x07 ; 7 | |
1e6: e1 f0 breq .+56 ; 0x220 <digitalWrite+0x90> | |
1e8: 28 30 cpi r18, 0x08 ; 8 | |
1ea: a1 f0 breq .+40 ; 0x214 <digitalWrite+0x84> | |
1ec: 24 30 cpi r18, 0x04 ; 4 | |
1ee: 09 f7 brne .-62 ; 0x1b2 <digitalWrite+0x22> | |
1f0: 90 91 80 00 lds r25, 0x0080 | |
1f4: 9f 7d andi r25, 0xDF ; 223 | |
1f6: 90 93 80 00 sts 0x0080, r25 | |
1fa: db cf rjmp .-74 ; 0x1b2 <digitalWrite+0x22> | |
1fc: 21 30 cpi r18, 0x01 ; 1 | |
1fe: 31 f0 breq .+12 ; 0x20c <digitalWrite+0x7c> | |
200: 22 30 cpi r18, 0x02 ; 2 | |
202: b9 f6 brne .-82 ; 0x1b2 <digitalWrite+0x22> | |
204: 94 b5 in r25, 0x24 ; 36 | |
206: 9f 7d andi r25, 0xDF ; 223 | |
208: 94 bd out 0x24, r25 ; 36 | |
20a: d3 cf rjmp .-90 ; 0x1b2 <digitalWrite+0x22> | |
20c: 94 b5 in r25, 0x24 ; 36 | |
20e: 9f 77 andi r25, 0x7F ; 127 | |
210: 94 bd out 0x24, r25 ; 36 | |
212: cf cf rjmp .-98 ; 0x1b2 <digitalWrite+0x22> | |
214: 90 91 b0 00 lds r25, 0x00B0 | |
218: 9f 7d andi r25, 0xDF ; 223 | |
21a: 90 93 b0 00 sts 0x00B0, r25 | |
21e: c9 cf rjmp .-110 ; 0x1b2 <digitalWrite+0x22> | |
220: 90 91 b0 00 lds r25, 0x00B0 | |
224: 9f 77 andi r25, 0x7F ; 127 | |
226: 90 93 b0 00 sts 0x00B0, r25 | |
22a: c3 cf rjmp .-122 ; 0x1b2 <digitalWrite+0x22> | |
22c: 90 91 80 00 lds r25, 0x0080 | |
230: 9f 77 andi r25, 0x7F ; 127 | |
232: 90 93 80 00 sts 0x0080, r25 | |
236: bd cf rjmp .-134 ; 0x1b2 <digitalWrite+0x22> | |
00000238 <digitalRead>: | |
238: 90 e0 ldi r25, 0x00 ; 0 | |
23a: fc 01 movw r30, r24 | |
23c: e8 59 subi r30, 0x98 ; 152 | |
23e: ff 4f sbci r31, 0xFF ; 255 | |
240: 24 91 lpm r18, Z | |
242: fc 01 movw r30, r24 | |
244: e4 58 subi r30, 0x84 ; 132 | |
246: ff 4f sbci r31, 0xFF ; 255 | |
248: 34 91 lpm r19, Z | |
24a: fc 01 movw r30, r24 | |
24c: e0 57 subi r30, 0x70 ; 112 | |
24e: ff 4f sbci r31, 0xFF ; 255 | |
250: 84 91 lpm r24, Z | |
252: 88 23 and r24, r24 | |
254: 91 f0 breq .+36 ; 0x27a <digitalRead+0x42> | |
256: 21 11 cpse r18, r1 | |
258: 13 c0 rjmp .+38 ; 0x280 <digitalRead+0x48> | |
25a: e8 2f mov r30, r24 | |
25c: f0 e0 ldi r31, 0x00 ; 0 | |
25e: ee 0f add r30, r30 | |
260: ff 1f adc r31, r31 | |
262: ec 55 subi r30, 0x5C ; 92 | |
264: ff 4f sbci r31, 0xFF ; 255 | |
266: a5 91 lpm r26, Z+ | |
268: b4 91 lpm r27, Z | |
26a: 2c 91 ld r18, X | |
26c: 23 23 and r18, r19 | |
26e: 81 e0 ldi r24, 0x01 ; 1 | |
270: 90 e0 ldi r25, 0x00 ; 0 | |
272: 09 f0 breq .+2 ; 0x276 <digitalRead+0x3e> | |
274: 08 95 ret | |
276: 80 e0 ldi r24, 0x00 ; 0 | |
278: 08 95 ret | |
27a: 80 e0 ldi r24, 0x00 ; 0 | |
27c: 90 e0 ldi r25, 0x00 ; 0 | |
27e: 08 95 ret | |
280: 23 30 cpi r18, 0x03 ; 3 | |
282: 29 f1 breq .+74 ; 0x2ce <digitalRead+0x96> | |
284: 60 f0 brcs .+24 ; 0x29e <digitalRead+0x66> | |
286: 27 30 cpi r18, 0x07 ; 7 | |
288: e1 f0 breq .+56 ; 0x2c2 <digitalRead+0x8a> | |
28a: 28 30 cpi r18, 0x08 ; 8 | |
28c: a1 f0 breq .+40 ; 0x2b6 <digitalRead+0x7e> | |
28e: 24 30 cpi r18, 0x04 ; 4 | |
290: 21 f7 brne .-56 ; 0x25a <digitalRead+0x22> | |
292: 90 91 80 00 lds r25, 0x0080 | |
296: 9f 7d andi r25, 0xDF ; 223 | |
298: 90 93 80 00 sts 0x0080, r25 | |
29c: de cf rjmp .-68 ; 0x25a <digitalRead+0x22> | |
29e: 21 30 cpi r18, 0x01 ; 1 | |
2a0: 31 f0 breq .+12 ; 0x2ae <digitalRead+0x76> | |
2a2: 22 30 cpi r18, 0x02 ; 2 | |
2a4: d1 f6 brne .-76 ; 0x25a <digitalRead+0x22> | |
2a6: 94 b5 in r25, 0x24 ; 36 | |
2a8: 9f 7d andi r25, 0xDF ; 223 | |
2aa: 94 bd out 0x24, r25 ; 36 | |
2ac: d6 cf rjmp .-84 ; 0x25a <digitalRead+0x22> | |
2ae: 94 b5 in r25, 0x24 ; 36 | |
2b0: 9f 77 andi r25, 0x7F ; 127 | |
2b2: 94 bd out 0x24, r25 ; 36 | |
2b4: d2 cf rjmp .-92 ; 0x25a <digitalRead+0x22> | |
2b6: 90 91 b0 00 lds r25, 0x00B0 | |
2ba: 9f 7d andi r25, 0xDF ; 223 | |
2bc: 90 93 b0 00 sts 0x00B0, r25 | |
2c0: cc cf rjmp .-104 ; 0x25a <digitalRead+0x22> | |
2c2: 90 91 b0 00 lds r25, 0x00B0 | |
2c6: 9f 77 andi r25, 0x7F ; 127 | |
2c8: 90 93 b0 00 sts 0x00B0, r25 | |
2cc: c6 cf rjmp .-116 ; 0x25a <digitalRead+0x22> | |
2ce: 90 91 80 00 lds r25, 0x0080 | |
2d2: 9f 77 andi r25, 0x7F ; 127 | |
2d4: 90 93 80 00 sts 0x0080, r25 | |
2d8: c0 cf rjmp .-128 ; 0x25a <digitalRead+0x22> | |
000002da <atexit>: | |
2da: 80 e0 ldi r24, 0x00 ; 0 | |
2dc: 90 e0 ldi r25, 0x00 ; 0 | |
2de: 08 95 ret | |
000002e0 <initVariant>: | |
2e0: 08 95 ret | |
000002e2 <__vector_16>: | |
2e2: 1f 92 push r1 | |
2e4: 0f 92 push r0 | |
2e6: 0f b6 in r0, 0x3f ; 63 | |
2e8: 0f 92 push r0 | |
2ea: 11 24 eor r1, r1 | |
2ec: 2f 93 push r18 | |
2ee: 3f 93 push r19 | |
2f0: 8f 93 push r24 | |
2f2: 9f 93 push r25 | |
2f4: af 93 push r26 | |
2f6: bf 93 push r27 | |
2f8: 80 91 00 01 lds r24, 0x0100 | |
2fc: 90 91 01 01 lds r25, 0x0101 | |
300: a0 91 02 01 lds r26, 0x0102 | |
304: b0 91 03 01 lds r27, 0x0103 | |
308: 30 91 08 01 lds r19, 0x0108 | |
30c: 23 e0 ldi r18, 0x03 ; 3 | |
30e: 23 0f add r18, r19 | |
310: 2d 37 cpi r18, 0x7D ; 125 | |
312: 68 f1 brcs .+90 ; 0x36e <__vector_16+0x8c> | |
314: 26 e8 ldi r18, 0x86 ; 134 | |
316: 23 0f add r18, r19 | |
318: 02 96 adiw r24, 0x02 ; 2 | |
31a: a1 1d adc r26, r1 | |
31c: b1 1d adc r27, r1 | |
31e: 20 93 08 01 sts 0x0108, r18 | |
322: 80 93 00 01 sts 0x0100, r24 | |
326: 90 93 01 01 sts 0x0101, r25 | |
32a: a0 93 02 01 sts 0x0102, r26 | |
32e: b0 93 03 01 sts 0x0103, r27 | |
332: 80 91 04 01 lds r24, 0x0104 | |
336: 90 91 05 01 lds r25, 0x0105 | |
33a: a0 91 06 01 lds r26, 0x0106 | |
33e: b0 91 07 01 lds r27, 0x0107 | |
342: 01 96 adiw r24, 0x01 ; 1 | |
344: a1 1d adc r26, r1 | |
346: b1 1d adc r27, r1 | |
348: 80 93 04 01 sts 0x0104, r24 | |
34c: 90 93 05 01 sts 0x0105, r25 | |
350: a0 93 06 01 sts 0x0106, r26 | |
354: b0 93 07 01 sts 0x0107, r27 | |
358: bf 91 pop r27 | |
35a: af 91 pop r26 | |
35c: 9f 91 pop r25 | |
35e: 8f 91 pop r24 | |
360: 3f 91 pop r19 | |
362: 2f 91 pop r18 | |
364: 0f 90 pop r0 | |
366: 0f be out 0x3f, r0 ; 63 | |
368: 0f 90 pop r0 | |
36a: 1f 90 pop r1 | |
36c: 18 95 reti | |
36e: 01 96 adiw r24, 0x01 ; 1 | |
370: a1 1d adc r26, r1 | |
372: b1 1d adc r27, r1 | |
374: d4 cf rjmp .-88 ; 0x31e <__vector_16+0x3c> | |
00000376 <millis>: | |
376: 2f b7 in r18, 0x3f ; 63 | |
378: f8 94 cli | |
37a: 60 91 00 01 lds r22, 0x0100 | |
37e: 70 91 01 01 lds r23, 0x0101 | |
382: 80 91 02 01 lds r24, 0x0102 | |
386: 90 91 03 01 lds r25, 0x0103 | |
38a: 2f bf out 0x3f, r18 ; 63 | |
38c: 08 95 ret | |
0000038e <micros>: | |
38e: 3f b7 in r19, 0x3f ; 63 | |
390: f8 94 cli | |
392: 80 91 04 01 lds r24, 0x0104 | |
396: 90 91 05 01 lds r25, 0x0105 | |
39a: a0 91 06 01 lds r26, 0x0106 | |
39e: b0 91 07 01 lds r27, 0x0107 | |
3a2: 26 b5 in r18, 0x26 ; 38 | |
3a4: a8 9b sbis 0x15, 0 ; 21 | |
3a6: 05 c0 rjmp .+10 ; 0x3b2 <micros+0x24> | |
3a8: 2f 3f cpi r18, 0xFF ; 255 | |
3aa: 19 f0 breq .+6 ; 0x3b2 <micros+0x24> | |
3ac: 01 96 adiw r24, 0x01 ; 1 | |
3ae: a1 1d adc r26, r1 | |
3b0: b1 1d adc r27, r1 | |
3b2: 3f bf out 0x3f, r19 ; 63 | |
3b4: 66 27 eor r22, r22 | |
3b6: 78 2f mov r23, r24 | |
3b8: 89 2f mov r24, r25 | |
3ba: 9a 2f mov r25, r26 | |
3bc: 62 0f add r22, r18 | |
3be: 71 1d adc r23, r1 | |
3c0: 81 1d adc r24, r1 | |
3c2: 91 1d adc r25, r1 | |
3c4: 66 0f add r22, r22 | |
3c6: 77 1f adc r23, r23 | |
3c8: 88 1f adc r24, r24 | |
3ca: 99 1f adc r25, r25 | |
3cc: 66 0f add r22, r22 | |
3ce: 77 1f adc r23, r23 | |
3d0: 88 1f adc r24, r24 | |
3d2: 99 1f adc r25, r25 | |
3d4: 08 95 ret | |
000003d6 <delay>: | |
3d6: cf 92 push r12 | |
3d8: df 92 push r13 | |
3da: ef 92 push r14 | |
3dc: ff 92 push r15 | |
3de: 0f 93 push r16 | |
3e0: 1f 93 push r17 | |
3e2: cf 93 push r28 | |
3e4: df 93 push r29 | |
3e6: 00 d0 rcall .+0 ; 0x3e8 <delay+0x12> | |
3e8: 00 d0 rcall .+0 ; 0x3ea <delay+0x14> | |
3ea: cd b7 in r28, 0x3d ; 61 | |
3ec: de b7 in r29, 0x3e ; 62 | |
3ee: 3f b7 in r19, 0x3f ; 63 | |
3f0: f8 94 cli | |
3f2: c0 90 04 01 lds r12, 0x0104 | |
3f6: d0 90 05 01 lds r13, 0x0105 | |
3fa: e0 90 06 01 lds r14, 0x0106 | |
3fe: f0 90 07 01 lds r15, 0x0107 | |
402: 26 b5 in r18, 0x26 ; 38 | |
404: a8 9b sbis 0x15, 0 ; 21 | |
406: 07 c0 rjmp .+14 ; 0x416 <delay+0x40> | |
408: 2f 3f cpi r18, 0xFF ; 255 | |
40a: 29 f0 breq .+10 ; 0x416 <delay+0x40> | |
40c: 4f ef ldi r20, 0xFF ; 255 | |
40e: c4 1a sub r12, r20 | |
410: d4 0a sbc r13, r20 | |
412: e4 0a sbc r14, r20 | |
414: f4 0a sbc r15, r20 | |
416: 3f bf out 0x3f, r19 ; 63 | |
418: fe 2c mov r15, r14 | |
41a: ed 2c mov r14, r13 | |
41c: dc 2c mov r13, r12 | |
41e: cc 24 eor r12, r12 | |
420: c2 0e add r12, r18 | |
422: d1 1c adc r13, r1 | |
424: e1 1c adc r14, r1 | |
426: f1 1c adc r15, r1 | |
428: cc 0c add r12, r12 | |
42a: dd 1c adc r13, r13 | |
42c: ee 1c adc r14, r14 | |
42e: ff 1c adc r15, r15 | |
430: cc 0c add r12, r12 | |
432: dd 1c adc r13, r13 | |
434: ee 1c adc r14, r14 | |
436: ff 1c adc r15, r15 | |
438: 86 01 movw r16, r12 | |
43a: 61 15 cp r22, r1 | |
43c: 71 05 cpc r23, r1 | |
43e: 81 05 cpc r24, r1 | |
440: 91 05 cpc r25, r1 | |
442: 09 f4 brne .+2 ; 0x446 <delay+0x70> | |
444: 41 c0 rjmp .+130 ; 0x4c8 <delay+0xf2> | |
446: 69 83 std Y+1, r22 ; 0x01 | |
448: 7a 83 std Y+2, r23 ; 0x02 | |
44a: 8b 83 std Y+3, r24 ; 0x03 | |
44c: 9c 83 std Y+4, r25 ; 0x04 | |
44e: 0e 94 b7 02 call 0x56e ; 0x56e <yield> | |
452: 3f b7 in r19, 0x3f ; 63 | |
454: f8 94 cli | |
456: c0 90 04 01 lds r12, 0x0104 | |
45a: d0 90 05 01 lds r13, 0x0105 | |
45e: e0 90 06 01 lds r14, 0x0106 | |
462: f0 90 07 01 lds r15, 0x0107 | |
466: 26 b5 in r18, 0x26 ; 38 | |
468: 69 81 ldd r22, Y+1 ; 0x01 | |
46a: 7a 81 ldd r23, Y+2 ; 0x02 | |
46c: 8b 81 ldd r24, Y+3 ; 0x03 | |
46e: 9c 81 ldd r25, Y+4 ; 0x04 | |
470: a8 9b sbis 0x15, 0 ; 21 | |
472: 07 c0 rjmp .+14 ; 0x482 <delay+0xac> | |
474: 2f 3f cpi r18, 0xFF ; 255 | |
476: 29 f0 breq .+10 ; 0x482 <delay+0xac> | |
478: ef ef ldi r30, 0xFF ; 255 | |
47a: ce 1a sub r12, r30 | |
47c: de 0a sbc r13, r30 | |
47e: ee 0a sbc r14, r30 | |
480: fe 0a sbc r15, r30 | |
482: 3f bf out 0x3f, r19 ; 63 | |
484: fe 2c mov r15, r14 | |
486: ed 2c mov r14, r13 | |
488: dc 2c mov r13, r12 | |
48a: cc 24 eor r12, r12 | |
48c: c2 0e add r12, r18 | |
48e: d1 1c adc r13, r1 | |
490: e1 1c adc r14, r1 | |
492: f1 1c adc r15, r1 | |
494: cc 0c add r12, r12 | |
496: dd 1c adc r13, r13 | |
498: ee 1c adc r14, r14 | |
49a: ff 1c adc r15, r15 | |
49c: cc 0c add r12, r12 | |
49e: dd 1c adc r13, r13 | |
4a0: ee 1c adc r14, r14 | |
4a2: ff 1c adc r15, r15 | |
4a4: 96 01 movw r18, r12 | |
4a6: 20 1b sub r18, r16 | |
4a8: 31 0b sbc r19, r17 | |
4aa: 28 3e cpi r18, 0xE8 ; 232 | |
4ac: 33 40 sbci r19, 0x03 ; 3 | |
4ae: 28 f2 brcs .-118 ; 0x43a <delay+0x64> | |
4b0: 61 50 subi r22, 0x01 ; 1 | |
4b2: 71 09 sbc r23, r1 | |
4b4: 81 09 sbc r24, r1 | |
4b6: 91 09 sbc r25, r1 | |
4b8: 08 51 subi r16, 0x18 ; 24 | |
4ba: 1c 4f sbci r17, 0xFC ; 252 | |
4bc: 61 15 cp r22, r1 | |
4be: 71 05 cpc r23, r1 | |
4c0: 81 05 cpc r24, r1 | |
4c2: 91 05 cpc r25, r1 | |
4c4: 09 f0 breq .+2 ; 0x4c8 <delay+0xf2> | |
4c6: bf cf rjmp .-130 ; 0x446 <delay+0x70> | |
4c8: 0f 90 pop r0 | |
4ca: 0f 90 pop r0 | |
4cc: 0f 90 pop r0 | |
4ce: 0f 90 pop r0 | |
4d0: df 91 pop r29 | |
4d2: cf 91 pop r28 | |
4d4: 1f 91 pop r17 | |
4d6: 0f 91 pop r16 | |
4d8: ff 90 pop r15 | |
4da: ef 90 pop r14 | |
4dc: df 90 pop r13 | |
4de: cf 90 pop r12 | |
4e0: 08 95 ret | |
000004e2 <delayMicroseconds>: | |
4e2: 82 30 cpi r24, 0x02 ; 2 | |
4e4: 91 05 cpc r25, r1 | |
4e6: 38 f0 brcs .+14 ; 0x4f6 <delayMicroseconds+0x14> | |
4e8: 88 0f add r24, r24 | |
4ea: 99 1f adc r25, r25 | |
4ec: 88 0f add r24, r24 | |
4ee: 99 1f adc r25, r25 | |
4f0: 05 97 sbiw r24, 0x05 ; 5 | |
4f2: 01 97 sbiw r24, 0x01 ; 1 | |
4f4: f1 f7 brne .-4 ; 0x4f2 <delayMicroseconds+0x10> | |
4f6: 08 95 ret | |
000004f8 <init>: | |
4f8: 78 94 sei | |
4fa: 84 b5 in r24, 0x24 ; 36 | |
4fc: 82 60 ori r24, 0x02 ; 2 | |
4fe: 84 bd out 0x24, r24 ; 36 | |
500: 84 b5 in r24, 0x24 ; 36 | |
502: 81 60 ori r24, 0x01 ; 1 | |
504: 84 bd out 0x24, r24 ; 36 | |
506: 85 b5 in r24, 0x25 ; 37 | |
508: 82 60 ori r24, 0x02 ; 2 | |
50a: 85 bd out 0x25, r24 ; 37 | |
50c: 85 b5 in r24, 0x25 ; 37 | |
50e: 81 60 ori r24, 0x01 ; 1 | |
510: 85 bd out 0x25, r24 ; 37 | |
512: ee e6 ldi r30, 0x6E ; 110 | |
514: f0 e0 ldi r31, 0x00 ; 0 | |
516: 80 81 ld r24, Z | |
518: 81 60 ori r24, 0x01 ; 1 | |
51a: 80 83 st Z, r24 | |
51c: e1 e8 ldi r30, 0x81 ; 129 | |
51e: f0 e0 ldi r31, 0x00 ; 0 | |
520: 10 82 st Z, r1 | |
522: 80 81 ld r24, Z | |
524: 82 60 ori r24, 0x02 ; 2 | |
526: 80 83 st Z, r24 | |
528: 80 81 ld r24, Z | |
52a: 81 60 ori r24, 0x01 ; 1 | |
52c: 80 83 st Z, r24 | |
52e: e0 e8 ldi r30, 0x80 ; 128 | |
530: f0 e0 ldi r31, 0x00 ; 0 | |
532: 80 81 ld r24, Z | |
534: 81 60 ori r24, 0x01 ; 1 | |
536: 80 83 st Z, r24 | |
538: e1 eb ldi r30, 0xB1 ; 177 | |
53a: f0 e0 ldi r31, 0x00 ; 0 | |
53c: 80 81 ld r24, Z | |
53e: 84 60 ori r24, 0x04 ; 4 | |
540: 80 83 st Z, r24 | |
542: e0 eb ldi r30, 0xB0 ; 176 | |
544: f0 e0 ldi r31, 0x00 ; 0 | |
546: 80 81 ld r24, Z | |
548: 81 60 ori r24, 0x01 ; 1 | |
54a: 80 83 st Z, r24 | |
54c: ea e7 ldi r30, 0x7A ; 122 | |
54e: f0 e0 ldi r31, 0x00 ; 0 | |
550: 80 81 ld r24, Z | |
552: 84 60 ori r24, 0x04 ; 4 | |
554: 80 83 st Z, r24 | |
556: 80 81 ld r24, Z | |
558: 82 60 ori r24, 0x02 ; 2 | |
55a: 80 83 st Z, r24 | |
55c: 80 81 ld r24, Z | |
55e: 81 60 ori r24, 0x01 ; 1 | |
560: 80 83 st Z, r24 | |
562: 80 81 ld r24, Z | |
564: 80 68 ori r24, 0x80 ; 128 | |
566: 80 83 st Z, r24 | |
568: 10 92 c1 00 sts 0x00C1, r1 | |
56c: 08 95 ret | |
0000056e <yield>: | |
56e: 08 95 ret | |
00000570 <main>: | |
570: 0e 94 7c 02 call 0x4f8 ; 0x4f8 <init> | |
574: 0e 94 70 01 call 0x2e0 ; 0x2e0 <initVariant> | |
578: 0e 94 75 00 call 0xea ; 0xea <setup> | |
57c: 80 e0 ldi r24, 0x00 ; 0 | |
57e: 90 e0 ldi r25, 0x00 ; 0 | |
580: 89 2b or r24, r25 | |
582: 29 f0 breq .+10 ; 0x58e <main+0x1e> | |
584: 0e 94 89 00 call 0x112 ; 0x112 <loop> | |
588: 0e 94 00 00 call 0 ; 0x0 <__vectors> | |
58c: fb cf rjmp .-10 ; 0x584 <main+0x14> | |
58e: 0e 94 89 00 call 0x112 ; 0x112 <loop> | |
592: 0e 94 89 00 call 0x112 ; 0x112 <loop> | |
596: fb cf rjmp .-10 ; 0x58e <main+0x1e> | |
00000598 <_exit>: | |
598: f8 94 cli | |
0000059a <__stop_program>: | |
59a: ff cf rjmp .-2 ; 0x59a <__stop_program> |
解説
C++11
コンパイラは Arduino.app に入っている avr-gcc を使っているが -std=c++11 を指定して C++11 の機能を有効にしている (constexpr 関数) なので素の Arduino.app からだとコンパイルできない。
Arduino ビルトイン関数の再実装
Arduino 側で portOutputRegister digitalPinToBitMask digitalPinToPort といった関数が定義されており、これらは PROGMEM からテーブルをひいてくる実装になっているので、まずこれをコンパイル時にできるように constexpr 関数で再実装した。
C++14 ならもっと簡単に書けるはずなんだけど、C++11 相当だと関数本体に return 以外書けないのでキモい実装になっている。
digitalWriteMulti
ここがキモで、まず digitalWriteMulti でうけて、digitalWriteMulti_ で再帰的に処理している。digitalWriteMulti_ の最初の3引数は、持ってまわっている状態で、残りは元の digitalWriteMulti に渡された引数。
C++ のテンプレートメタプログラミングではこのようにパターンマッチでしか可変長引数を扱えないみたい。だけど思ったより綺麗に実装できた気がする。
WRITE_MULTI() マクロ
これはプリプロセッサマクロで単に置換している。テンプレート引数として渡すのが気持ち悪かったので(慣れかもしれない)マクロでラップしている。
その他
C++ はほとんど書いたことがないので、きっともっといい方法がありそうだと思う。特にテンプレートメタプログラミングで可変長引数を処理するとき、状態を全てテンプレート引数の頭にフラットに渡しているのがダサい。うまくコンパイル時だけ使えるコンテナみたいなのを持ちまわしていければよかったが、おもいつかなかった。
pinMode にも応用できると思うが pinMode は PORTx もいじるのでとりあえず省略した。
大きなメリット
同じようなことはテンプレートを使わない場合(素のCとか)だとまずできない。
特に「指定しなかった部分のビットはかえない」を実現しようとすると、どうしてもビットマスクと実際に設定するビット値の2つを扱わないといけないので、かなりコードが煩雑になる。テンプレート化することで表面上の可読性がかなり上がる (テンプレート部分はアレだけど)
そしてコンパイル時にチェックができる点はおおきい。マイコンはどうしてもフィードバックがすくないので、実行時エラーというのは実際気付くのが難しい。
速度的にも当然メリットがある。これの場合はコンパイルしたあとは素で書く場合と完全に同じバイナリになる。
000000ea <setup>: ; PORTD = (PORTD & 0b11110000) | (0b1010); ea: 8b b1 in r24, 0x0b ; 11 ec: 80 7f andi r24, 0xF0 ; 240 ee: 8a 60 ori r24, 0x0A ; 10 f0: 8b b9 out 0x0b, r24 ; 11 ; asm volatile ("nop"); // marker f2: 00 00 nop ; WRITE_MULTI(...) f4: 8b b1 in r24, 0x0b ; 11 f6: 80 7f andi r24, 0xF0 ; 240 f8: 8a 60 ori r24, 0x0A ; 10 fa: 8b b9 out 0x0b, r24 ; 11
素の digitalWrite の場合
; digitalWrite(0, LOW); 10a: 60 e0 ldi r22, 0x00 ; 0 10c: 80 e0 ldi r24, 0x00 ; 0 10e: 0c 94 c8 00 jmp 0x190 ; 0x190 <digitalWrite>
で関数コールして
00000190 <digitalWrite>: 190: 90 e0 ldi r25, 0x00 ; 0 192: fc 01 movw r30, r24 194: e8 59 subi r30, 0x98 ; 152 196: ff 4f sbci r31, 0xFF ; 255 198: 24 91 lpm r18, Z 19a: fc 01 movw r30, r24 19c: e4 58 subi r30, 0x84 ; 132 19e: ff 4f sbci r31, 0xFF ; 255 1a0: 34 91 lpm r19, Z 1a2: fc 01 movw r30, r24 1a4: e0 57 subi r30, 0x70 ; 112 1a6: ff 4f sbci r31, 0xFF ; 255 1a8: 84 91 lpm r24, Z 1aa: 88 23 and r24, r24 1ac: 99 f0 breq .+38 ; 0x1d4 <digitalWrite+0x44> 1ae: 21 11 cpse r18, r1 1b0: 16 c0 rjmp .+44 ; 0x1de <digitalWrite+0x4e> 1b2: e8 2f mov r30, r24 1b4: f0 e0 ldi r31, 0x00 ; 0 1b6: ee 0f add r30, r30 1b8: ff 1f adc r31, r31 1ba: e2 55 subi r30, 0x52 ; 82 1bc: ff 4f sbci r31, 0xFF ; 255 1be: a5 91 lpm r26, Z+ 1c0: b4 91 lpm r27, Z 1c2: 8f b7 in r24, 0x3f ; 63 1c4: f8 94 cli 1c6: 9c 91 ld r25, X 1c8: 61 11 cpse r22, r1 1ca: 05 c0 rjmp .+10 ; 0x1d6 <digitalWrite+0x46> 1cc: 30 95 com r19 1ce: 93 23 and r25, r19 1d0: 9c 93 st X, r25 1d2: 8f bf out 0x3f, r24 ; 63 1d4: 08 95 ret 1d6: 93 2b or r25, r19 1d8: 9c 93 st X, r25 1da: 8f bf out 0x3f, r24 ; 63 1dc: fb cf rjmp .-10 ; 0x1d4 <digitalWrite+0x44> 1de: 23 30 cpi r18, 0x03 ; 3 1e0: 29 f1 breq .+74 ; 0x22c <digitalWrite+0x9c> 1e2: 60 f0 brcs .+24 ; 0x1fc <digitalWrite+0x6c> 1e4: 27 30 cpi r18, 0x07 ; 7 1e6: e1 f0 breq .+56 ; 0x220 <digitalWrite+0x90> 1e8: 28 30 cpi r18, 0x08 ; 8 1ea: a1 f0 breq .+40 ; 0x214 <digitalWrite+0x84> 1ec: 24 30 cpi r18, 0x04 ; 4 1ee: 09 f7 brne .-62 ; 0x1b2 <digitalWrite+0x22> 1f0: 90 91 80 00 lds r25, 0x0080 1f4: 9f 7d andi r25, 0xDF ; 223 1f6: 90 93 80 00 sts 0x0080, r25 1fa: db cf rjmp .-74 ; 0x1b2 <digitalWrite+0x22> 1fc: 21 30 cpi r18, 0x01 ; 1 1fe: 31 f0 breq .+12 ; 0x20c <digitalWrite+0x7c> 200: 22 30 cpi r18, 0x02 ; 2 202: b9 f6 brne .-82 ; 0x1b2 <digitalWrite+0x22> 204: 94 b5 in r25, 0x24 ; 36 206: 9f 7d andi r25, 0xDF ; 223 208: 94 bd out 0x24, r25 ; 36 20a: d3 cf rjmp .-90 ; 0x1b2 <digitalWrite+0x22> 20c: 94 b5 in r25, 0x24 ; 36 20e: 9f 77 andi r25, 0x7F ; 127 210: 94 bd out 0x24, r25 ; 36 212: cf cf rjmp .-98 ; 0x1b2 <digitalWrite+0x22> 214: 90 91 b0 00 lds r25, 0x00B0 218: 9f 7d andi r25, 0xDF ; 223 21a: 90 93 b0 00 sts 0x00B0, r25 21e: c9 cf rjmp .-110 ; 0x1b2 <digitalWrite+0x22> 220: 90 91 b0 00 lds r25, 0x00B0 224: 9f 77 andi r25, 0x7F ; 127 226: 90 93 b0 00 sts 0x00B0, r25 22a: c3 cf rjmp .-122 ; 0x1b2 <digitalWrite+0x22> 22c: 90 91 80 00 lds r25, 0x0080 230: 9f 77 andi r25, 0x7F ; 127 232: 90 93 80 00 sts 0x0080, r25 236: bd cf rjmp .-134 ; 0x1b2 <digitalWrite+0x22>
となっていて、1bit 書くだけでかなり大層なことをしていることがわかる。