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,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