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,61 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ parse_operands('____ __kk kkkk ksss') do |cpu, operands|
7
+ {
8
+ k: Value.new(twos_complement(operands.fetch(:k).value, 7)),
9
+ s: Value.new(operands.fetch(:s).value ? 1 : 0),
10
+ }
11
+ end
12
+
13
+ decode('1111 00kk kkkk ksss', :brbs) do |cpu, _opcode_definition, operands|
14
+ cpu.instruction(:brbs, operands.fetch(:s), operands.fetch(:k))
15
+ end
16
+
17
+ opcode(:brbs, %i[sreg_flag near_relative_pc]) do |cpu, _memory, args|
18
+ cpu.next_pc = cpu.pc + args.fetch(1).value + 1 if args.fetch(0).value == 1
19
+ end
20
+
21
+ decode('1111 01kk kkkk ksss', :brbc) do |cpu, _opcode_definition, operands|
22
+ cpu.instruction(:brbc, operands.fetch(:s), operands.fetch(:k))
23
+ end
24
+
25
+ opcode(:brbc, %i[sreg_flag near_relative_pc]) do |cpu, _memory, args|
26
+ cpu.next_pc = cpu.pc + args.fetch(1).value + 1 if args.fetch(0).value == 0
27
+ end
28
+
29
+ decode('0001 00rd dddd rrrr', :cpse) do |cpu, _opcode_definition, operands|
30
+ cpu.instruction(:cpse, operands.fetch(:Rd), operands.fetch(:Rr))
31
+ end
32
+
33
+ opcode(:cpse, %i[register register]) do |cpu, _memory, args|
34
+ cpu.decode if args.fetch(0).value == args.fetch(1).value
35
+ end
36
+
37
+ decode('1111 110r rrrr 0bbb', :sbrc) do |cpu, _opcode_definition, operands|
38
+ register_bit = RegisterWithBitNumber.new(
39
+ T.cast(operands.fetch(:Rr), MemoryByteRegister),
40
+ operands.fetch(:b).value
41
+ )
42
+ cpu.instruction(:sbrc, register_bit)
43
+ end
44
+
45
+ opcode(:sbrc, %i[register_with_bit_number]) do |cpu, _memory, args|
46
+ cpu.decode if args.fetch(0).value == 0
47
+ end
48
+
49
+ decode('1111 111r rrrr 0bbb', :sbrs) do |cpu, _opcode_definition, operands|
50
+ register_bit = RegisterWithBitNumber.new(
51
+ T.cast(operands.fetch(:Rr), MemoryByteRegister),
52
+ operands.fetch(:b).value
53
+ )
54
+ cpu.instruction(:sbrs, register_bit)
55
+ end
56
+
57
+ opcode(:sbrs, %i[register_with_bit_number]) do |cpu, _memory, args|
58
+ cpu.decode if args.fetch(0).value == 1
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('1001 0101 0000 1000', :ret) do |cpu, _opcode_definition, _operands|
7
+ cpu.instruction(:ret)
8
+ end
9
+
10
+ opcode(:ret) do |cpu, _memory, _args|
11
+ cpu.next_pc = stack_pop_word(cpu)
12
+ end
13
+
14
+ decode('1001 0101 0001 1000', :reti) do |cpu, _opcode_definition, _operands|
15
+ cpu.instruction(:reti)
16
+ end
17
+
18
+ opcode(:reti, %i[], %i[I]) do |cpu, _memory, _args|
19
+ cpu.sreg.I = true
20
+ cpu.next_pc = stack_pop_word(cpu)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,74 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('1001 0100 0000 1100', :jmp) do |cpu, _opcode_definition, _operands|
7
+ k = cpu.fetch
8
+ cpu.instruction(:jmp, Value.new(k))
9
+ end
10
+
11
+ decode('1001 010k kkkk 110k', :jmp) do |cpu, _opcode_definition, operands|
12
+ k = cpu.fetch
13
+ cpu.instruction(:jmp, Value.new(operands.fetch(:k).value << 16 | k))
14
+ end
15
+
16
+ opcode(:jmp, %i[absolute_pc]) do |cpu, _memory, args|
17
+ cpu.next_pc = args.fetch(0).value
18
+ end
19
+
20
+ decode('1001 0100 0000 1110', :call) do |cpu, _opcode_definition, _operands|
21
+ k = cpu.fetch
22
+ cpu.instruction(:call, Value.new(k))
23
+ end
24
+
25
+ decode('1001 010k kkkk 111k', :call) do |cpu, _opcode_definition, operands|
26
+ k = cpu.fetch
27
+ cpu.instruction(:call, Value.new(operands.fetch(:k).value << 16 | k))
28
+ end
29
+
30
+ opcode(:call, %i[absolute_pc]) do |cpu, _memory, args|
31
+ stack_push_word(cpu, cpu.pc + 2)
32
+ cpu.next_pc = args.fetch(0).value
33
+ end
34
+
35
+ # rcall rjmp
36
+ parse_operands('____ kkkk kkkk kkkk') do |_cpu, operands|
37
+ { k: Value.new(twos_complement(operands.fetch(:k).value, 12)) }
38
+ end
39
+
40
+ decode('1100 kkkk kkkk kkkk', :rjmp) do |cpu, _opcode_definition, operands|
41
+ cpu.instruction(:rjmp, operands.fetch(:k))
42
+ end
43
+
44
+ opcode(:rjmp, %i[far_relative_pc]) do |cpu, _memory, args|
45
+ cpu.next_pc = cpu.pc + args.fetch(0).value + 1
46
+ end
47
+
48
+ decode('1101 kkkk kkkk kkkk', :rcall) do |cpu, _opcode_definition, operands|
49
+ cpu.instruction(:rcall, operands.fetch(:k))
50
+ end
51
+
52
+ opcode(:rcall, %i[far_relative_pc]) do |cpu, _memory, args|
53
+ stack_push_word(cpu, cpu.pc + 1)
54
+ cpu.next_pc = cpu.pc + args.fetch(0).value + 1
55
+ end
56
+
57
+ decode('1001 0100 0000 1001', :ijmp) do |cpu, _opcode_definition, _operands|
58
+ cpu.instruction(:ijmp)
59
+ end
60
+
61
+ opcode(:ijmp) do |cpu, _memory, _args|
62
+ cpu.next_pc = cpu.Z.value
63
+ end
64
+
65
+ decode('1001 0101 0000 1001', :icall) do |cpu, _opcode_definition, _operands|
66
+ cpu.instruction(:icall)
67
+ end
68
+
69
+ opcode(:icall) do |cpu, _memory, _args|
70
+ stack_push_word(cpu, cpu.pc + 1)
71
+ cpu.next_pc = cpu.Z.value
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,14 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('1001 0101 1001 1000', :break) do |cpu, _opcode_definition, _operands|
7
+ cpu.instruction(:break)
8
+ end
9
+
10
+ opcode(:break) do |_cpu, _memory, _args|
11
+ # Do nothing.
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,66 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ # rubocop:disable Naming/MethodParameterName
7
+ # rubocop:disable Layout/SpaceAroundOperators
8
+ sig { params(cpu: CPU, r: Integer, rd: Integer, rr_k: Integer, mnemonic: Symbol).void }
9
+ def self.set_sreg_for_cp_cpi_cpc(cpu, r, rd, rr_k, mnemonic)
10
+ b7 = (1<<7)
11
+ r7 = (r & b7) != 0
12
+ rd7 = (rd & b7) != 0
13
+ rr_k7 = (rr_k & b7) != 0
14
+ r3 = (r & b7) != 0
15
+ rd3 = (rd & b7) != 0
16
+ rr_k3 = (rr_k & b7) != 0
17
+ n = r7
18
+ v = rd7 & rr_k7 & r7 | !rd7 & rr_k7 & r7
19
+ c = !rd7 & rr_k7 | rr_k7 & r7 | r7 & !rd7
20
+ h = !rd3 & rr_k3 | rr_k3 & r3 | r3 & !rd3
21
+
22
+ z = r.zero?
23
+ z = r.zero? ? cpu.sreg.Z : false if mnemonic == :cpc
24
+
25
+ cpu.sreg.from_h(
26
+ {
27
+ H: h,
28
+ S: n ^ v,
29
+ V: v,
30
+ N: n,
31
+ Z: z,
32
+ C: c,
33
+ }
34
+ )
35
+ end
36
+ # rubocop:enable Layout/SpaceAroundOperators
37
+ # rubocop:enable Naming/MethodParameterName
38
+
39
+ decode('0001 01rd dddd rrrr', :cp) do |cpu, _opcode_definition, operands|
40
+ cpu.instruction(:cp, operands.fetch(:Rd), operands.fetch(:Rr))
41
+ end
42
+
43
+ opcode(:cp, %i[register register], %i[H S V N Z C]) do |cpu, _memory, args|
44
+ result = (args.fetch(0).value - args.fetch(1).value) & 0xff
45
+ set_sreg_for_cp_cpi_cpc(cpu, result, args.fetch(0).value, args.fetch(1).value, :cp)
46
+ end
47
+
48
+ decode('0000 01rd dddd rrrr', :cpc) do |cpu, _opcode_definition, operands|
49
+ cpu.instruction(:cpc, operands.fetch(:Rd), operands.fetch(:Rr))
50
+ end
51
+
52
+ opcode(:cpc, %i[register register], %i[H S V N Z C]) do |cpu, _memory, args|
53
+ result = (args.fetch(0).value - args.fetch(1).value - (cpu.sreg.C ? 1 : 0)) & 0xff
54
+ set_sreg_for_cp_cpi_cpc(cpu, result, args.fetch(0).value, args.fetch(1).value, :cpc)
55
+ end
56
+
57
+ decode('0011 KKKK dddd KKKK', :cpi) do |cpu, _opcode_definition, operands|
58
+ cpu.instruction(:cpi, operands.fetch(:Rd), operands.fetch(:K))
59
+ end
60
+
61
+ opcode(:cpi, %i[register byte], %i[H S V N Z C]) do |cpu, _memory, args|
62
+ result = (args.fetch(0).value - args.fetch(1).value) & 0xff
63
+ set_sreg_for_cp_cpi_cpc(cpu, result, args.fetch(0).value, args.fetch(1).value, :cpi)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,14 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('1110 KKKK dddd KKKK', :ldi) do |cpu, _opcode_definition, operands|
7
+ cpu.instruction(:ldi, operands.fetch(:Rd), operands.fetch(:K))
8
+ end
9
+
10
+ opcode(:ldi, %i[register byte]) do |_cpu, _memory, args|
11
+ args.fetch(0).value = args.fetch(1).value
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('1001 0101 1100 1000', :lpm) do |cpu, _opcode_definition, _operands|
7
+ cpu.instruction(:lpm, cpu.r0, RegisterWithModification.new(cpu.Z))
8
+ end
9
+
10
+ decode('1001 000d dddd 0100', :lpm) do |cpu, _opcode_definition, operands|
11
+ cpu.instruction(:lpm, operands.fetch(:Rd), RegisterWithModification.new(cpu.Z))
12
+ end
13
+
14
+ decode('1001 000d dddd 0101', :lpm) do |cpu, _opcode_definition, operands|
15
+ cpu.instruction(:lpm, operands.fetch(:Rd), RegisterWithModification.new(cpu.Z, :post_increment))
16
+ end
17
+
18
+ opcode(:lpm, %i[register modifying_word_register]) do |cpu, _memory, args|
19
+ mwr = T.cast(args.fetch(1), RegisterWithModification)
20
+ mwr.register.value -= 1 if mwr.modification == :pre_decrement
21
+ args.fetch(0).value = cpu.device.flash.memory.fetch(mwr.register.value).value
22
+ mwr.register.value += 1 if mwr.modification == :post_increment
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,222 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('1001 000d dddd 0000', :lds) do |cpu, _opcode_definition, operands|
7
+ k = cpu.fetch
8
+ cpu.instruction(:lds, operands.fetch(:Rd).value, k)
9
+ end
10
+
11
+ parse_operands('____ _kkk dddd kkkk') do |cpu, operands|
12
+ {
13
+ Rd: cpu.registers.fetch(operands.fetch(:d).value),
14
+ k: bit_jumble_for_lds_sts(operands.fetch(:k).value),
15
+ }
16
+ end
17
+
18
+ decode('1010 0kkk dddd kkkk', :lds) do |cpu, _opcode_definition, operands|
19
+ cpu.instruction(:lds, operands.fetch(:Rd), operands.fetch(:k))
20
+ end
21
+
22
+ opcode(:lds, %i[register word]) do |cpu, _memory, args|
23
+ cpu.next_pc += 1
24
+ args.fetch(0).value = cpu.sram.memory.fetch(args.fetch(1).value).value
25
+ end
26
+
27
+ decode('1001 000d dddd 1100', :ld) do |cpu, _opcode_definition, operands|
28
+ cpu.instruction(:ld, operands.fetch(:Rd), RegisterWithModification.new(cpu.X))
29
+ end
30
+
31
+ decode('1001 000d dddd 1101', :ld) do |cpu, _opcode_definition, operands|
32
+ cpu.instruction(:ld, operands.fetch(:Rd), RegisterWithModification.new(cpu.X, :post_increment))
33
+ end
34
+
35
+ decode('1001 000d dddd 1110', :ld) do |cpu, _opcode_definition, operands|
36
+ cpu.instruction(:ld, operands.fetch(:Rd), RegisterWithModification.new(cpu.X, :pre_decrement))
37
+ end
38
+
39
+ decode('1000 000d dddd 1000', :ld) do |cpu, _opcode_definition, operands|
40
+ cpu.instruction(:ld, operands.fetch(:Rd), RegisterWithModification.new(cpu.Y))
41
+ end
42
+
43
+ decode('1001 000d dddd 1001', :ld) do |cpu, _opcode_definition, operands|
44
+ cpu.instruction(:ld, operands.fetch(:Rd), RegisterWithModification.new(cpu.Y, :post_increment))
45
+ end
46
+
47
+ decode('1001 000d dddd 1010', :ld) do |cpu, _opcode_definition, operands|
48
+ cpu.instruction(:ld, operands.fetch(:Rd), RegisterWithModification.new(cpu.Y, :pre_decrement))
49
+ end
50
+
51
+ decode('1000 000d dddd 0000', :ld) do |cpu, _opcode_definition, operands|
52
+ cpu.instruction(:ld, operands.fetch(:Rd), RegisterWithModification.new(cpu.Z))
53
+ end
54
+
55
+ decode('1001 000d dddd 0001', :ld) do |cpu, _opcode_definition, operands|
56
+ cpu.instruction(:ld, operands.fetch(:Rd), RegisterWithModification.new(cpu.Z, :post_increment))
57
+ end
58
+
59
+ decode('1001 000d dddd 0010', :ld) do |cpu, _opcode_definition, operands|
60
+ cpu.instruction(:ld, operands.fetch(:Rd), RegisterWithModification.new(cpu.Z, :pre_decrement))
61
+ end
62
+
63
+ opcode(:ld, %i[register modifying_word_register]) do |cpu, _memory, args|
64
+ mwr = T.cast(args.fetch(1), RegisterWithModification)
65
+ mwr.register.value -= 1 if mwr.modification == :pre_decrement
66
+ args.fetch(0).value = cpu.sram.memory.fetch(mwr.register.value).value
67
+ mwr.register.value += 1 if mwr.modification == :post_increment
68
+ end
69
+
70
+ parse_operands('__q_ qq_d dddd _qqq') do |cpu, operands|
71
+ {
72
+ Rd: cpu.registers.fetch(operands.fetch(:d).value),
73
+ q: operands.fetch(:q),
74
+ }
75
+ end
76
+
77
+ decode('10q0 qq0d dddd 1qqq', :ldd) do |cpu, _opcode_definition, operands|
78
+ cpu.instruction(:ldd, operands.fetch(:Rd), RegisterWithDisplacement.new(cpu.Y, operands.fetch(:q).value))
79
+ end
80
+
81
+ decode('10q0 qq0d dddd 0qqq', :ldd) do |cpu, _opcode_definition, operands|
82
+ cpu.instruction(:ldd, operands.fetch(:Rd), RegisterWithDisplacement.new(cpu.Z, operands.fetch(:q).value))
83
+ end
84
+
85
+ opcode(:ldd, %i[register displaced_word_register]) do |cpu, _memory, args|
86
+ dwr = T.cast(args.fetch(1), RegisterWithDisplacement)
87
+ args.fetch(0).value = cpu.sram.memory.fetch(dwr.register.value + dwr.displacement).value
88
+ end
89
+
90
+ decode('1001 001r rrrr 0000', :sts) do |cpu, _opcode_definition, operands|
91
+ k = cpu.fetch
92
+ cpu.instruction(:sts, k, operands.fetch(:Rr))
93
+ end
94
+
95
+ parse_operands('____ _kkk rrrr kkkk') do |cpu, operands|
96
+ {
97
+ Rr: cpu.registers.fetch(operands.fetch(:r).value),
98
+ k: bit_jumble_for_lds_sts(operands.fetch(:k).value),
99
+ }
100
+ end
101
+
102
+ decode('1010 0kkk rrrr kkkk', :sts) do |cpu, _opcode_definition, operands|
103
+ cpu.instruction(:sts, operands.fetch(:k), operands.fetch(:Rr))
104
+ end
105
+
106
+ opcode(:sts, %i[word register]) do |cpu, _memory, args|
107
+ cpu.next_pc += 1
108
+ cpu.sram.memory.fetch(args.fetch(0).value).value = args.fetch(1).value
109
+ end
110
+
111
+ decode('1001 001r rrrr 1100', :st) do |cpu, _opcode_definition, operands|
112
+ cpu.instruction(:st, cpu.X, operands.fetch(:Rr))
113
+ end
114
+
115
+ decode('1001 001r rrrr 1101', :st) do |cpu, _opcode_definition, operands|
116
+ cpu.instruction(:st, RegisterWithModification.new(cpu.X, :post_increment), operands.fetch(:Rr))
117
+ end
118
+
119
+ decode('1001 001r rrrr 1110', :st) do |cpu, _opcode_definition, operands|
120
+ cpu.instruction(:st, RegisterWithModification.new(cpu.X, :pre_decrement), operands.fetch(:Rr))
121
+ end
122
+
123
+ decode('1000 001r rrrr 1000', :st) do |cpu, _opcode_definition, operands|
124
+ cpu.instruction(:st, RegisterWithModification.new(cpu.Y), operands.fetch(:Rr))
125
+ end
126
+
127
+ decode('1001 001r rrrr 1001', :st) do |cpu, _opcode_definition, operands|
128
+ cpu.instruction(:st, RegisterWithModification.new(cpu.Y, :post_increment), operands.fetch(:Rr))
129
+ end
130
+
131
+ decode('1001 001r rrrr 1010', :st) do |cpu, _opcode_definition, operands|
132
+ cpu.instruction(:st, RegisterWithModification.new(cpu.Y, :pre_decrement), operands.fetch(:Rr))
133
+ end
134
+
135
+ decode('1000 001r rrrr 0000', :st) do |cpu, _opcode_definition, operands|
136
+ cpu.instruction(:st, RegisterWithModification.new(cpu.Z), operands.fetch(:Rr))
137
+ end
138
+
139
+ decode('1001 001r rrrr 0001', :st) do |cpu, _opcode_definition, operands|
140
+ cpu.instruction(:st, RegisterWithModification.new(cpu.Z, :post_increment), operands.fetch(:Rr))
141
+ end
142
+
143
+ decode('1001 001r rrrr 0010', :st) do |cpu, _opcode_definition, operands|
144
+ cpu.instruction(:st, RegisterWithModification.new(cpu.Z, :pre_decrement), operands.fetch(:Rr))
145
+ end
146
+
147
+ opcode(:st, %i[modifying_word_register register]) do |cpu, _memory, args|
148
+ mwr = T.cast(args.fetch(0), RegisterWithModification)
149
+ mwr.register.value -= 1 if mwr.modification == :pre_decrement
150
+ cpu.sram.memory.fetch(mwr.register.value).value = args.fetch(1).value
151
+ mwr.register.value += 1 if mwr.modification == :post_increment
152
+ end
153
+
154
+ parse_operands('__q_ qq_r rrrr _qqq') do |cpu, operands|
155
+ {
156
+ Rr: cpu.registers.fetch(operands.fetch(:r).value),
157
+ q: operands.fetch(:q),
158
+ }
159
+ end
160
+
161
+ decode('10q0 qq1r rrrr 1qqq', :std) do |cpu, _opcode_definition, operands|
162
+ cpu.instruction(:std, RegisterWithDisplacement.new(cpu.Y, operands.fetch(:q).value), operands.fetch(:Rr))
163
+ end
164
+
165
+ decode('10q0 qq1r rrrr 0qqq', :std) do |cpu, _opcode_definition, operands|
166
+ cpu.instruction(:std, RegisterWithDisplacement.new(cpu.Z, operands.fetch(:q).value), operands.fetch(:Rr))
167
+ end
168
+
169
+ opcode(:std, %i[displaced_word_register register]) do |cpu, _memory, args|
170
+ dwr = T.cast(args.fetch(0), RegisterWithDisplacement)
171
+ cpu.sram.memory.fetch(dwr.register.value + dwr.displacement).value = args.fetch(1).value
172
+ end
173
+
174
+ sig { params(memory_byte: MemoryByte, register: Value, mnemonic: Symbol).void }
175
+ def self.exchange_memory_byte_with_register(memory_byte, register, mnemonic)
176
+ old_value = memory_byte.value
177
+ case mnemonic
178
+ when :xch
179
+ memory_byte.value = register.value
180
+ when :las
181
+ memory_byte.value = register.value | old_value
182
+ when :lac
183
+ memory_byte.value = (~register.value & old_value) & 0xff
184
+ when :lat
185
+ memory_byte.value = register.value ^ old_value
186
+ end
187
+ register.value = old_value
188
+ end
189
+
190
+ decode('1001 001r rrrr 0100', :xch) do |cpu, _opcode_definition, operands|
191
+ cpu.instruction(:xch, operands.fetch(:Rr))
192
+ end
193
+
194
+ opcode(:xch, %i[register]) do |cpu, _memory, args|
195
+ exchange_memory_byte_with_register(cpu.sram.memory.fetch(cpu.Z.value), args.fetch(0), :xch)
196
+ end
197
+
198
+ decode('1001 001r rrrr 0101', :las) do |cpu, _opcode_definition, operands|
199
+ cpu.instruction(:las, operands.fetch(:Rr))
200
+ end
201
+
202
+ opcode(:las, %i[register]) do |cpu, _memory, args|
203
+ exchange_memory_byte_with_register(cpu.sram.memory.fetch(cpu.Z.value), args.fetch(0), :las)
204
+ end
205
+
206
+ decode('1001 001r rrrr 0110', :lac) do |cpu, _opcode_definition, operands|
207
+ cpu.instruction(:lac, operands.fetch(:Rr))
208
+ end
209
+
210
+ opcode(:lac, %i[register]) do |cpu, _memory, args|
211
+ exchange_memory_byte_with_register(cpu.sram.memory.fetch(cpu.Z.value), args.fetch(0), :lac)
212
+ end
213
+
214
+ decode('1001 001r rrrr 0111', :lat) do |cpu, _opcode_definition, operands|
215
+ cpu.instruction(:lat, operands.fetch(:Rr))
216
+ end
217
+
218
+ opcode(:lat, %i[register]) do |cpu, _memory, args|
219
+ exchange_memory_byte_with_register(cpu.sram.memory.fetch(cpu.Z.value), T.cast(args.fetch(0), Register), :lat)
220
+ end
221
+ end
222
+ end