avruby 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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