avruby 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +28 -0
  3. data/README.md +17 -0
  4. data/bin/avruby_shell +162 -0
  5. data/lib/avr.rb +41 -0
  6. data/lib/avr/argument.rb +23 -0
  7. data/lib/avr/clock.rb +99 -0
  8. data/lib/avr/cpu.rb +254 -0
  9. data/lib/avr/device.rb +249 -0
  10. data/lib/avr/device/atmel_atmega328p.rb +181 -0
  11. data/lib/avr/instruction.rb +72 -0
  12. data/lib/avr/memory.rb +163 -0
  13. data/lib/avr/memory/eeprom.rb +65 -0
  14. data/lib/avr/memory/flash.rb +13 -0
  15. data/lib/avr/memory/memory_byte.rb +54 -0
  16. data/lib/avr/memory/sram.rb +13 -0
  17. data/lib/avr/opcode.rb +237 -0
  18. data/lib/avr/opcode/branch/conditional.rb +61 -0
  19. data/lib/avr/opcode/branch/return.rb +23 -0
  20. data/lib/avr/opcode/branch/unconditional.rb +74 -0
  21. data/lib/avr/opcode/break.rb +14 -0
  22. data/lib/avr/opcode/compare.rb +66 -0
  23. data/lib/avr/opcode/data/immediate.rb +14 -0
  24. data/lib/avr/opcode/data/program.rb +25 -0
  25. data/lib/avr/opcode/data/sram.rb +222 -0
  26. data/lib/avr/opcode/data/stack.rb +22 -0
  27. data/lib/avr/opcode/io/bit.rb +22 -0
  28. data/lib/avr/opcode/io/in_out.rb +38 -0
  29. data/lib/avr/opcode/math/addition.rb +120 -0
  30. data/lib/avr/opcode/math/bitwise.rb +170 -0
  31. data/lib/avr/opcode/math/multiplication.rb +23 -0
  32. data/lib/avr/opcode/math/subtraction.rb +137 -0
  33. data/lib/avr/opcode/nop.rb +14 -0
  34. data/lib/avr/opcode/opcodes.rb +24 -0
  35. data/lib/avr/opcode/operand_parsers.rb +75 -0
  36. data/lib/avr/opcode/register.rb +37 -0
  37. data/lib/avr/opcode/sleep.rb +14 -0
  38. data/lib/avr/opcode/sreg.rb +56 -0
  39. data/lib/avr/opcode/wdr.rb +14 -0
  40. data/lib/avr/opcode_decoder.rb +202 -0
  41. data/lib/avr/oscillator.rb +33 -0
  42. data/lib/avr/port.rb +107 -0
  43. data/lib/avr/register.rb +18 -0
  44. data/lib/avr/register/memory_byte_register.rb +27 -0
  45. data/lib/avr/register/memory_byte_register_with_named_bits.rb +85 -0
  46. data/lib/avr/register/register_file.rb +59 -0
  47. data/lib/avr/register/register_pair.rb +46 -0
  48. data/lib/avr/register/sp.rb +41 -0
  49. data/lib/avr/register/sreg.rb +12 -0
  50. data/lib/avr/register_with_bit_number.rb +40 -0
  51. data/lib/avr/register_with_displacement.rb +31 -0
  52. data/lib/avr/register_with_modification.rb +35 -0
  53. data/lib/avr/register_with_named_bit.rb +36 -0
  54. data/lib/avr/value.rb +45 -0
  55. data/lib/avr/version.rb +6 -0
  56. metadata +182 -0
@@ -0,0 +1,22 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('1001 001r rrrr 1111', :push) do |cpu, _opcode_definition, operands|
7
+ cpu.instruction(:push, operands.fetch(:Rr))
8
+ end
9
+
10
+ opcode(:push, %i[register]) do |cpu, _memory, args|
11
+ stack_push(cpu, args.fetch(0).value)
12
+ end
13
+
14
+ decode('1001 000d dddd 1111', :pop) do |cpu, _opcode_definition, operands|
15
+ cpu.instruction(:pop, operands.fetch(:Rd))
16
+ end
17
+
18
+ opcode(:pop, %i[register]) do |cpu, _memory, args|
19
+ args.fetch(0).value = stack_pop(cpu)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('1001 1000 AAAA Abbb', :cbi) do |cpu, _opcode_definition, operands|
7
+ cpu.instruction(:cbi, operands.fetch(:A), operands.fetch(:b))
8
+ end
9
+
10
+ opcode(:cbi, %i[lower_io_address bit_number]) do |cpu, _memory, args|
11
+ cpu.sram.memory.fetch(cpu.device.io_register_start + args.fetch(0).value).value &= ~(1 << args.fetch(1).value)
12
+ end
13
+
14
+ decode('1001 1010 AAAA Abbb', :sbi) do |cpu, _opcode_definition, operands|
15
+ cpu.instruction(:sbi, operands.fetch(:A), operands.fetch(:b))
16
+ end
17
+
18
+ opcode(:sbi, %i[lower_io_address bit_number]) do |cpu, _memory, args|
19
+ cpu.sram.memory.fetch(cpu.device.io_register_start + args.fetch(0).value).value |= (1 << args.fetch(1).value)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,38 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ parse_operands('____ _AAd dddd AAAA') do |cpu, operands|
7
+ {
8
+ Rd: cpu.registers.fetch(operands.fetch(:d).value),
9
+ A: operands.fetch(:A),
10
+ }
11
+ end
12
+
13
+ decode('1011 0AAd dddd AAAA', :in) do |cpu, _opcode_definition, operands|
14
+ cpu.instruction(:in, operands.fetch(:Rd), operands.fetch(:A))
15
+ end
16
+
17
+ opcode(:in, %i[register io_address]) do |cpu, _memory, args|
18
+ reg = cpu.device.io_registers.fetch(args.fetch(1).value)
19
+ args.fetch(0).value = cpu.send(T.must(reg)).value
20
+ end
21
+
22
+ parse_operands('____ _AAr rrrr AAAA') do |cpu, operands|
23
+ {
24
+ Rr: cpu.registers.fetch(operands.fetch(:r).value),
25
+ A: operands.fetch(:A),
26
+ }
27
+ end
28
+
29
+ decode('1011 1AAr rrrr AAAA', :out) do |cpu, _opcode_definition, operands|
30
+ cpu.instruction(:out, operands.fetch(:A), operands.fetch(:Rr))
31
+ end
32
+
33
+ opcode(:out, %i[io_address register]) do |cpu, _memory, args|
34
+ reg = cpu.device.io_registers.fetch(args.fetch(0).value)
35
+ cpu.send(T.must(reg)).value = args.fetch(1).value
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,120 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ # rubocop:disable Naming/MethodParameterName
7
+ sig { params(cpu: CPU, r: Integer, rd: Integer).void }
8
+ def self.set_sreg_for_inc(cpu, r, rd)
9
+ n = (r & (1 << 7)) != 0
10
+ v = (rd == 0x7f)
11
+
12
+ cpu.sreg.from_h(
13
+ {
14
+ S: n ^ v,
15
+ V: v,
16
+ N: n,
17
+ Z: r.zero?,
18
+ }
19
+ )
20
+ end
21
+ # rubocop:enable Naming/MethodParameterName
22
+
23
+ decode('1001 101d dddd 0011', :inc) do |cpu, _opcode_definition, operands|
24
+ cpu.instruction(:inc, operands.fetch(:Rd))
25
+ end
26
+
27
+ opcode(:inc, %i[register], %i[S V N Z]) do |cpu, _memory, args|
28
+ result = (args.fetch(0).value + 1) & 0xff
29
+ set_sreg_for_inc(cpu, result, args.fetch(0).value)
30
+ args.fetch(0).value = result
31
+ end
32
+
33
+ # rubocop:disable Naming/MethodParameterName
34
+ sig { params(cpu: CPU, r: Integer, rd: Integer, rr: Integer).void }
35
+ def self.set_sreg_for_add_adc(cpu, r, rd, rr)
36
+ b7 = (1 << 7)
37
+ r7 = (r & b7) != 0
38
+ rd7 = (rd & b7) != 0
39
+ rr7 = (rr & b7) != 0
40
+ r3 = (r & b7) != 0
41
+ rd3 = (rd & b7) != 0
42
+ rr3 = (rr & b7) != 0
43
+ n = r7
44
+ v = rd7 & rr7 & !r7 | !rd7 & !rr7 & r7
45
+ c = rd7 & rr7 | rr7 & !r7 | !r7 & rd7
46
+ h = rd3 & rr3 | rr3 & !r3 | !r3 & rd3
47
+
48
+ cpu.sreg.from_h(
49
+ {
50
+ H: h,
51
+ S: n ^ v,
52
+ V: v,
53
+ N: n,
54
+ Z: r.zero?,
55
+ C: c,
56
+ }
57
+ )
58
+ end
59
+ # rubocop:enable Naming/MethodParameterName
60
+
61
+ decode('0000 11rd dddd rrrr', :add) do |cpu, _opcode_definition, operands|
62
+ if operands.fetch(:Rd).value == operands.fetch(:Rr).value
63
+ cpu.instruction(:lsl, operands.fetch(:Rd))
64
+ else
65
+ cpu.instruction(:add, operands.fetch(:Rd), operands.fetch(:Rr))
66
+ end
67
+ end
68
+
69
+ opcode(:add, %i[register register], %i[H S V N Z C]) do |cpu, _memory, args|
70
+ result = (args.fetch(0).value + args.fetch(1).value) & 0xff
71
+ set_sreg_for_add_adc(cpu, result, args.fetch(0).value, args.fetch(1).value)
72
+ args.fetch(0).value = result
73
+ end
74
+
75
+ decode('0001 11rd dddd rrrr', :adc) do |cpu, _opcode_definition, operands|
76
+ cpu.instruction(:adc, operands.fetch(:Rd), operands.fetch(:Rr))
77
+ end
78
+
79
+ opcode(:adc, %i[register register], %i[H S V N Z C]) do |cpu, _memory, args|
80
+ result = (args.fetch(0).value + args.fetch(1).value + (cpu.sreg.C ? 1 : 0)) & 0xff
81
+ set_sreg_for_add_adc(cpu, result, args.fetch(0).value, args.fetch(1).value)
82
+ args.fetch(0).value = result
83
+ end
84
+
85
+ # rubocop:disable Naming/MethodParameterName
86
+ # rubocop:disable Layout/SpaceAroundOperators
87
+ sig { params(cpu: CPU, r: Integer, rd: Integer).void }
88
+ def self.set_sreg_for_adiw(cpu, r, rd)
89
+ b15 = (1 << 15)
90
+ b7 = (1 << 7)
91
+ rdh7 = (rd & b7) != 0
92
+ r15 = (r & b15) != 0
93
+ v = !rdh7 & r15
94
+ n = r15
95
+ c = !r15 & rdh7
96
+
97
+ cpu.sreg.from_h(
98
+ {
99
+ S: n ^ v,
100
+ V: v,
101
+ N: n,
102
+ Z: r.zero?,
103
+ C: c,
104
+ }
105
+ )
106
+ end
107
+ # rubocop:enable Layout/SpaceAroundOperators
108
+ # rubocop:enable Naming/MethodParameterName
109
+
110
+ decode('1001 0110 KKdd KKKK', :adiw) do |cpu, _opcode_definition, operands|
111
+ cpu.instruction(:adiw, operands.fetch(:Rd), operands.fetch(:K))
112
+ end
113
+
114
+ opcode(:adiw, %i[word_register byte], %i[S V N Z C]) do |cpu, _memory, args|
115
+ result = (args.fetch(0).value + args.fetch(1).value) & 0xffff
116
+ set_sreg_for_adiw(cpu, result, args.fetch(0).value)
117
+ args.fetch(0).value = result
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,170 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ sig { params(cpu: CPU, value: Integer).void }
7
+ def self.set_sreg_for_and_or(cpu, value)
8
+ r7 = (value & (1 << 7)) != 0
9
+
10
+ cpu.sreg.from_h(
11
+ {
12
+ S: r7 ^ false,
13
+ V: false,
14
+ N: r7,
15
+ Z: value.zero?,
16
+ }
17
+ )
18
+ end
19
+
20
+ decode('0010 00rd dddd rrrr', :and) do |cpu, _opcode_definition, operands|
21
+ cpu.instruction(:and, operands.fetch(:Rd), operands.fetch(:Rr))
22
+ end
23
+
24
+ opcode(:and, %i[register register], %i[S V N Z]) do |cpu, _memory, args|
25
+ result = (args.fetch(0).value & args.fetch(1).value)
26
+ set_sreg_for_and_or(cpu, result)
27
+ args.fetch(0).value = result
28
+ end
29
+
30
+ decode('0111 KKKK dddd KKKK', :andi) do |cpu, _opcode_definition, operands|
31
+ cpu.instruction(:andi, operands.fetch(:Rd), operands.fetch(:K))
32
+ end
33
+
34
+ opcode(:andi, %i[register byte], %i[S V N Z]) do |cpu, _memory, args|
35
+ result = (args.fetch(0).value & args.fetch(1).value)
36
+ set_sreg_for_and_or(cpu, result)
37
+ args.fetch(0).value = result
38
+ end
39
+
40
+ decode('0010 01rd dddd rrrr', :eor) do |cpu, _opcode_definition, operands|
41
+ cpu.instruction(:eor, operands.fetch(:Rd), operands.fetch(:Rr))
42
+ end
43
+
44
+ opcode(:eor, %i[register register], %i[S V N Z]) do |cpu, _memory, args|
45
+ result = (args.fetch(0).value ^ args.fetch(1).value)
46
+ set_sreg_for_and_or(cpu, result)
47
+ args.fetch(0).value = result
48
+ end
49
+
50
+ decode('0010 10rd dddd rrrr', :or) do |cpu, _opcode_definition, operands|
51
+ cpu.instruction(:or, operands.fetch(:Rd), operands.fetch(:Rr))
52
+ end
53
+
54
+ opcode(:or, %i[register register], %i[S V N Z]) do |cpu, _memory, args|
55
+ result = (args.fetch(0).value | args.fetch(1).value)
56
+ set_sreg_for_and_or(cpu, result)
57
+ args.fetch(0).value = result
58
+ end
59
+
60
+ decode('0110 KKKK dddd KKKK', :ori) do |cpu, _opcode_definition, operands|
61
+ cpu.instruction(:ori, operands.fetch(:Rd), operands.fetch(:K))
62
+ end
63
+
64
+ opcode(:ori, %i[register byte], %i[S V N Z]) do |cpu, _memory, args|
65
+ result = (args.fetch(0).value | args.fetch(1).value)
66
+ set_sreg_for_and_or(cpu, result)
67
+ args.fetch(0).value = result
68
+ end
69
+
70
+ decode('1001 010d dddd 0010', :swap) do |cpu, _opcode_definition, operands|
71
+ cpu.instruction(:swap, operands.fetch(:Rd))
72
+ end
73
+
74
+ opcode(:swap, %i[register]) do |_cpu, _memory, args|
75
+ result = ((args.fetch(0).value & 0xf0) >> 4) | ((args.fetch(0).value & 0x0f) << 4)
76
+ args.fetch(0).value = result
77
+ end
78
+
79
+ decode('1001 010d dddd 0000', :com) do |cpu, _opcode_definition, operands|
80
+ cpu.instruction(:com, operands.fetch(:Rd))
81
+ end
82
+
83
+ opcode(:com, %i[register], %i[S V N Z C]) do |cpu, _memory, args|
84
+ result = 0xff - args.fetch(0).value
85
+ cpu.sreg.from_h(
86
+ {
87
+ S: ((result & 0x80) != 0) ^ false,
88
+ V: false,
89
+ N: (result & 0x80) != 0,
90
+ Z: result.zero?,
91
+ C: true,
92
+ }
93
+ )
94
+ args.fetch(0).value = result
95
+ end
96
+
97
+ # There is no specific opcode for LSL Rd; it is encoded as ADD Rd, Rd.
98
+ # decode('0000 11dd dddd dddd', :lsl) ...
99
+
100
+ opcode(:lsl, %i[register], %i[H S V N Z C]) do |cpu, _memory, args|
101
+ result = (args.fetch(0).value << 1) & 0xff
102
+
103
+ h = (args.fetch(0).value & (1 << 3)) != 0
104
+ n = (result & (1 << 7)) != 0
105
+ c = (args.fetch(0).value & (1 << 7)) != 0
106
+ v = n ^ c
107
+ s = n ^ v
108
+ cpu.sreg.from_h(
109
+ {
110
+ H: h,
111
+ S: s,
112
+ V: v,
113
+ N: n,
114
+ Z: result.zero?,
115
+ C: c,
116
+ }
117
+ )
118
+
119
+ args.fetch(0).value = result
120
+ end
121
+
122
+ decode('1001 010d dddd 0110', :lsr) do |cpu, _opcode_definition, operands|
123
+ cpu.instruction(:lsr, operands.fetch(:Rd))
124
+ end
125
+
126
+ opcode(:lsr, %i[register], %i[S V N Z C]) do |cpu, _memory, args|
127
+ result = args.fetch(0).value >> 1
128
+
129
+ n = false
130
+ c = (args.fetch(0).value & 1) != 0
131
+ v = n ^ c
132
+ s = n ^ v
133
+ cpu.sreg.from_h(
134
+ {
135
+ S: s,
136
+ V: v,
137
+ N: n,
138
+ Z: result.zero?,
139
+ C: c,
140
+ }
141
+ )
142
+
143
+ args.fetch(0).value = result
144
+ end
145
+
146
+ decode('1001 010d dddd 0101', :asr) do |cpu, _opcode_definition, operands|
147
+ cpu.instruction(:asr, operands.fetch(:Rd))
148
+ end
149
+
150
+ opcode(:asr, %i[register], %i[S V N Z C]) do |cpu, _memory, args|
151
+ result = (args.fetch(0).value >> 1) | (args.fetch(0).value & 0x80)
152
+
153
+ n = (result & (1 << 7)) != 0
154
+ c = (args.fetch(0).value & 1) != 0
155
+ v = n ^ c
156
+ s = n ^ v
157
+ cpu.sreg.from_h(
158
+ {
159
+ S: s,
160
+ V: v,
161
+ N: n,
162
+ Z: result.zero?,
163
+ C: c,
164
+ }
165
+ )
166
+
167
+ args.fetch(0).value = result
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('1001 11rd dddd rrrr', :mul) do |cpu, _opcode_definition, operands|
7
+ cpu.instruction(:mul, operands.fetch(:Rd), operands.fetch(:Rr))
8
+ end
9
+
10
+ opcode(:mul, %i[register register], %i[Z C]) do |cpu, _memory, args|
11
+ result = (args.fetch(0).value * args.fetch(1).value)
12
+ set_sreg_for_inc(cpu, result, args.fetch(0).value)
13
+ cpu.sreg.from_h(
14
+ {
15
+ Z: result.zero?,
16
+ C: (result & 0x8000) != 0,
17
+ }
18
+ )
19
+ cpu.r0 = result & 0x00ff
20
+ cpu.r1 = (result & 0xff00) >> 8
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,137 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ # rubocop:disable Naming/MethodParameterName
7
+ sig { params(cpu: CPU, r: Integer, rd: Integer).void }
8
+ def self.set_sreg_for_dec(cpu, r, rd)
9
+ n = (r & (1 << 7)) != 0
10
+ v = (rd == 0x80)
11
+
12
+ cpu.sreg.from_h(
13
+ {
14
+ S: n ^ v,
15
+ V: v,
16
+ N: n,
17
+ Z: r.zero?,
18
+ }
19
+ )
20
+ end
21
+ # rubocop:enable Naming/MethodParameterName
22
+
23
+ decode('1001 010d dddd 1010', :dec) do |cpu, _opcode_definition, operands|
24
+ cpu.instruction(:dec, operands.fetch(:Rd))
25
+ end
26
+
27
+ opcode(:dec, %i[register], %i[S V N Z]) do |cpu, _memory, args|
28
+ result = (args.fetch(0).value - 1) & 0xff
29
+ set_sreg_for_dec(cpu, result, args.fetch(0).value)
30
+ args.fetch(0).value = result
31
+ end
32
+
33
+ # rubocop:disable Naming/MethodParameterName
34
+ sig { params(cpu: CPU, r: Integer, rd: Integer, rr: Integer).void }
35
+ def self.set_sreg_for_sub_sbc(cpu, r, rd, rr)
36
+ b7 = (1 << 7)
37
+ r7 = (r & b7) != 0
38
+ rd7 = (rd & b7) != 0
39
+ rr7 = (rr & b7) != 0
40
+ r3 = (r & b7) != 0
41
+ rd3 = (rd & b7) != 0
42
+ rr3 = (rr & b7) != 0
43
+
44
+ n = r7
45
+ v = rd7 & rr7 & !r7 | !rd7 & rr7 & r7
46
+ c = !rd7 & rr7 | rr7 & r7 | r7 & !rd7
47
+ h = !rd3 & rr3 | rr3 & r3 | r3 & !rd3
48
+
49
+ cpu.sreg.from_h(
50
+ {
51
+ H: h,
52
+ S: n ^ v,
53
+ V: v,
54
+ N: n,
55
+ Z: r.zero?,
56
+ C: c,
57
+ }
58
+ )
59
+ end
60
+ # rubocop:enable Naming/MethodParameterName
61
+
62
+ decode('0001 10rd dddd rrrr', :sub) do |cpu, _opcode_definition, operands|
63
+ cpu.instruction(:sub, operands.fetch(:Rd), operands.fetch(:Rr))
64
+ end
65
+
66
+ opcode(:sub, %i[register register], %i[H S V N Z C]) do |cpu, _memory, args|
67
+ result = (args.fetch(0).value - args.fetch(1).value) & 0xff
68
+ set_sreg_for_sub_sbc(cpu, result, args.fetch(0).value, args.fetch(1).value)
69
+ args.fetch(0).value = result
70
+ end
71
+
72
+ decode('0101 KKKK dddd KKKK', :subi) do |cpu, _opcode_definition, operands|
73
+ cpu.instruction(:subi, operands.fetch(:Rd), operands.fetch(:K))
74
+ end
75
+
76
+ opcode(:subi, %i[register byte], %i[H S V N Z C]) do |cpu, _memory, args|
77
+ result = (args.fetch(0).value - args.fetch(1).value) & 0xff
78
+ set_sreg_for_sub_sbc(cpu, result, args.fetch(0).value, args.fetch(1).value)
79
+ args.fetch(0).value = result
80
+ end
81
+
82
+ decode('0000 10rd dddd rrrr', :sbc) do |cpu, _opcode_definition, operands|
83
+ cpu.instruction(:sbc, operands.fetch(:Rd), operands.fetch(:Rr))
84
+ end
85
+
86
+ opcode(:sbc, %i[register register], %i[H S V N Z C]) do |cpu, _memory, args|
87
+ result = (args.fetch(0).value - args.fetch(1).value - (cpu.sreg.C ? 1 : 0)) & 0xff
88
+ set_sreg_for_sub_sbc(cpu, result, args.fetch(0).value, args.fetch(1).value)
89
+ args.fetch(0).value = result
90
+ end
91
+
92
+ decode('0100 KKKK dddd KKKK', :sbci) do |cpu, _opcode_definition, operands|
93
+ cpu.instruction(:sbci, operands.fetch(:Rd), operands.fetch(:K))
94
+ end
95
+
96
+ opcode(:sbci, %i[register byte], %i[H S V N Z C]) do |cpu, _memory, args|
97
+ result = (args.fetch(0).value - args.fetch(1).value - (cpu.sreg.C ? 1 : 0)) & 0xff
98
+ set_sreg_for_sub_sbc(cpu, result, args.fetch(0).value, args.fetch(1).value)
99
+ args.fetch(0).value = result
100
+ end
101
+
102
+ # rubocop:disable Naming/MethodParameterName
103
+ # rubocop:disable Layout/SpaceAroundOperators
104
+ sig { params(cpu: CPU, r: Integer, rd: Integer).void }
105
+ def self.set_sreg_for_sbiw(cpu, r, rd)
106
+ b15 = (1 << 15)
107
+ b7 = (1 << 7)
108
+ rdh7 = (rd & b7) != 0
109
+ r15 = (r & b15) != 0
110
+ v = r15 & !rdh7
111
+ n = r15
112
+ c = r15 & !rdh7
113
+
114
+ cpu.sreg.from_h(
115
+ {
116
+ S: n ^ v,
117
+ V: v,
118
+ N: n,
119
+ Z: r.zero?,
120
+ C: c,
121
+ }
122
+ )
123
+ end
124
+ # rubocop:enable Layout/SpaceAroundOperators
125
+ # rubocop:enable Naming/MethodParameterName
126
+
127
+ decode('1001 0111 KKdd KKKK', :sbiw) do |cpu, _opcode_definition, operands|
128
+ cpu.instruction(:sbiw, operands.fetch(:Rd), operands.fetch(:K))
129
+ end
130
+
131
+ opcode(:sbiw, %i[word_register byte], %i[S V N Z C]) do |cpu, _memory, args|
132
+ result = (args.fetch(0).value - args.fetch(1).value) & 0xffff
133
+ set_sreg_for_sbiw(cpu, result, args.fetch(0).value)
134
+ args.fetch(0).value = result
135
+ end
136
+ end
137
+ end