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,14 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('0000 0000 0000 0000', :nop) do |cpu, _opcode_definition, _operands|
7
+ cpu.instruction(:nop)
8
+ end
9
+
10
+ opcode(:nop) do |_cpu, _memory, _args|
11
+ # Do nothing.
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require 'avr/opcode/operand_parsers'
5
+ require 'avr/opcode/nop'
6
+ require 'avr/opcode/break'
7
+ require 'avr/opcode/sleep'
8
+ require 'avr/opcode/wdr'
9
+ require 'avr/opcode/sreg'
10
+ require 'avr/opcode/register'
11
+ require 'avr/opcode/compare'
12
+ require 'avr/opcode/data/stack'
13
+ require 'avr/opcode/data/immediate'
14
+ require 'avr/opcode/data/program'
15
+ require 'avr/opcode/data/sram'
16
+ require 'avr/opcode/branch/unconditional'
17
+ require 'avr/opcode/branch/conditional'
18
+ require 'avr/opcode/branch/return'
19
+ require 'avr/opcode/math/addition'
20
+ require 'avr/opcode/math/subtraction'
21
+ require 'avr/opcode/math/multiplication'
22
+ require 'avr/opcode/math/bitwise'
23
+ require 'avr/opcode/io/bit'
24
+ require 'avr/opcode/io/in_out'
@@ -0,0 +1,75 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ sig { params(value: Integer, bits: Integer).returns(Integer) }
7
+ def self.twos_complement(value, bits)
8
+ mask = (2**(bits - 1)).to_i
9
+ -(value & mask) + (value & ~mask)
10
+ end
11
+
12
+ sig { params(k_in: Integer).returns(Integer) }
13
+ def self.bit_jumble_for_lds_sts(k_in)
14
+ k_out = k_in & 0b00001111
15
+ k_out |= k_in & 0b01100000 >> 1
16
+ k_out |= k_in & 0b00010000 << 2
17
+ k_out |= ~(k_in & 0b00010000 << 3) & 0b10000000
18
+ k_out
19
+ end
20
+
21
+ # adc add and cp cpc cpse eor mov mul muls or sbc sub
22
+ parse_operands('____ __rd dddd rrrr') do |cpu, operands|
23
+ {
24
+ Rd: cpu.registers.fetch(operands.fetch(:d).value),
25
+ Rr: cpu.registers.fetch(operands.fetch(:r).value),
26
+ }
27
+ end
28
+
29
+ # fmul fmuls fmulsu mulsu
30
+ parse_operands('____ ____ _ddd _rrr') do |cpu, operands|
31
+ {
32
+ Rd: cpu.registers.fetch(operands.fetch(:d).value | 0b10000),
33
+ Rr: cpu.registers.fetch(operands.fetch(:r).value | 0b10000),
34
+ }
35
+ end
36
+
37
+ # asr com dec elpm inc ld lds lpm lsr neg pop ror swap
38
+ parse_operands('____ ___d dddd ____') do |cpu, operands|
39
+ {
40
+ Rd: cpu.registers.fetch(operands.fetch(:d).value),
41
+ }
42
+ end
43
+
44
+ # lac las lat push st xch
45
+ parse_operands('____ ___r rrrr ____') do |cpu, operands|
46
+ {
47
+ Rr: cpu.registers.fetch(operands.fetch(:r).value),
48
+ }
49
+ end
50
+
51
+ # sbrc sbrs
52
+ parse_operands('____ ___r rrrr _bbb') do |cpu, operands|
53
+ {
54
+ Rr: cpu.registers.fetch(operands.fetch(:r).value),
55
+ b: Value.new(operands.fetch(:b).value),
56
+ }
57
+ end
58
+
59
+ # adiw sbiw
60
+ parse_operands('____ ____ KKdd KKKK') do |cpu, operands|
61
+ {
62
+ Rd: cpu.registers.associated_word_register(cpu.registers.fetch((operands.fetch(:d).value << 1) | 0b11000)),
63
+ K: Value.new(operands.fetch(:K).value),
64
+ }
65
+ end
66
+
67
+ # andi cpi ldi ori sbci sbr subi
68
+ parse_operands('____ KKKK dddd KKKK') do |cpu, operands|
69
+ {
70
+ Rd: cpu.registers.fetch(operands.fetch(:d).value | 0b10000),
71
+ K: Value.new(operands.fetch(:K).value),
72
+ }
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,37 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('0010 11rd dddd rrrr', :mov) do |cpu, _opcode_definition, operands|
7
+ cpu.instruction(:mov, operands.fetch(:Rd), operands.fetch(:Rr))
8
+ end
9
+
10
+ opcode(:mov, %i[register register]) do |_cpu, _memory, args|
11
+ args.fetch(0).value = args.fetch(1).value
12
+ end
13
+
14
+ parse_operands('____ ____ dddd rrrr') do |cpu, operands|
15
+ {
16
+ Rd: RegisterPair.new(
17
+ cpu,
18
+ cpu.registers.fetch((operands.fetch(:d).value << 1) + 1),
19
+ cpu.registers.fetch(operands.fetch(:d).value << 1)
20
+ ),
21
+ Rr: RegisterPair.new(
22
+ cpu,
23
+ cpu.registers.fetch((operands.fetch(:r).value << 1) + 1),
24
+ cpu.registers.fetch(operands.fetch(:r).value << 1)
25
+ ),
26
+ }
27
+ end
28
+
29
+ decode('0000 0001 dddd rrrr', :movw) do |cpu, _opcode_definition, operands|
30
+ cpu.instruction(:movw, operands.fetch(:Rd), operands.fetch(:Rr))
31
+ end
32
+
33
+ opcode(:movw, %i[register_pair register_pair]) do |_cpu, _memory, args|
34
+ args.fetch(0).value = args.fetch(1).value
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,14 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('1001 0101 1000 1000', :sleep) do |cpu, _opcode_definition, _operands|
7
+ cpu.instruction(:sleep)
8
+ end
9
+
10
+ opcode(:sleep) do |cpu, memory, args|
11
+ # Do nothing.
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,56 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('1001 0100 0sss 1000', :bset) do |cpu, _opcode_definition, operands|
7
+ sreg_bit = RegisterWithNamedBit.new(
8
+ cpu.sreg,
9
+ SREG::STATUS_BITS.fetch(operands.fetch(:s).value)
10
+ )
11
+ cpu.instruction(:bset, sreg_bit)
12
+ end
13
+
14
+ opcode(:bset, %i[sreg_flag], %i[I T H S V N Z C]) do |cpu, _memory, args|
15
+ args.fetch(0).value = 1
16
+ end
17
+
18
+ decode('1001 0100 1sss 1000', :bclr) do |cpu, _opcode_definition, operands|
19
+ sreg_bit = RegisterWithNamedBit.new(
20
+ cpu.sreg,
21
+ SREG::STATUS_BITS.fetch(operands.fetch(:s).value)
22
+ )
23
+ cpu.instruction(:bclr, sreg_bit)
24
+ end
25
+
26
+ opcode(:bclr, %i[sreg_flag], %i[I T H S V N Z C]) do |cpu, _memory, args|
27
+ args.fetch(0).value = 0
28
+ end
29
+
30
+ parse_operands('____ ___d dddd _bbb') do |cpu, operands|
31
+ {
32
+ Rd: cpu.registers.fetch(operands.fetch(:d).value),
33
+ b: operands.fetch(:b),
34
+ }
35
+ end
36
+
37
+ decode('1111 100d dddd 0bbb', :bld) do |cpu, _opcode_definition, operands|
38
+ cpu.instruction(:bld, operands.fetch(:Rd), operands.fetch(:b))
39
+ end
40
+
41
+ opcode(:bld, %i[register bit_number]) do |cpu, _memory, args|
42
+ t_bit = 1 << args.fetch(1).value
43
+ t_value = cpu.sreg.T ? t_bit : 0
44
+ t_mask = ~t_bit & 0xff
45
+ args.fetch(0).value = (args.fetch(0).value & t_mask) | t_value
46
+ end
47
+
48
+ decode('1111 101d dddd 0bbb', :bst) do |cpu, _opcode_definition, operands|
49
+ cpu.instruction(:bst, operands.fetch(:Rd), operands.fetch(:b))
50
+ end
51
+
52
+ opcode(:bst, %i[register bit_number], %i[T]) do |cpu, _memory, args|
53
+ cpu.sreg.T = args.fetch(0).value & (1 << args.fetch(1).value) != 0
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,14 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Opcode
6
+ decode('1001 0101 1010 1000', :wdr) do |cpu, _opcode_definition, _operands|
7
+ cpu.instruction(:wdr)
8
+ end
9
+
10
+ opcode(:wdr) do |_cpu, _memory, _args|
11
+ # Do nothing for now.
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,202 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class OpcodeDecoder
6
+ extend T::Sig
7
+
8
+ class OpcodeDefinition
9
+ extend T::Sig
10
+
11
+ ProcType = T.type_alias do
12
+ T.proc.params(
13
+ cpu: CPU,
14
+ opcode_definition: OpcodeDefinition,
15
+ operands: Opcode::OperandValueHashType
16
+ ).returns(Instruction)
17
+ end
18
+
19
+ sig { returns(String) }
20
+ attr_reader :pattern
21
+
22
+ sig { returns(Symbol) }
23
+ attr_reader :mnemonic
24
+
25
+ sig { returns(ProcType) }
26
+ attr_reader :parse_proc
27
+
28
+ sig { params(pattern: String, mnemonic: Symbol, parse_proc: ProcType).void }
29
+ def initialize(pattern, mnemonic, parse_proc)
30
+ @pattern = T.let(pattern.gsub(/[^01a-zA-Z]/, ''), String)
31
+ raise "Incorrect pattern length for #{pattern}" unless @pattern.size == 16
32
+
33
+ @mnemonic = mnemonic
34
+ @parse_proc = parse_proc
35
+
36
+ @operand_pattern = T.let(nil, T.nilable(String))
37
+ @match_value = T.let(nil, T.nilable(Integer))
38
+ @match_mask = T.let(nil, T.nilable(Integer))
39
+ end
40
+
41
+ sig { returns(String) }
42
+ def operand_pattern
43
+ @operand_pattern ||= pattern.gsub(/[01]/, '_')
44
+ end
45
+
46
+ sig { returns(Integer) }
47
+ def match_value
48
+ @match_value ||= pattern.gsub(/[^01]/, '0').to_i(2)
49
+ end
50
+
51
+ sig { returns(Integer) }
52
+ def match_mask
53
+ @match_mask ||= pattern.gsub(/[01]/, '1').gsub(/[^01]/, '0').to_i(2)
54
+ end
55
+
56
+ sig { params(word: Integer).returns(T::Boolean) }
57
+ def match?(word)
58
+ word & match_mask == match_value
59
+ end
60
+
61
+ sig { params(word: Integer).returns(Argument::NamedValueType) }
62
+ def extract_operands(word)
63
+ operands = Hash.new(0)
64
+ mask = 0x10000
65
+ pattern.split('').each do |operand|
66
+ mask >>= 1
67
+ next if %w[0 1].include?(operand)
68
+
69
+ operands[operand.to_sym] <<= 1
70
+ operands[operand.to_sym] |= 1 if (word & mask) != 0
71
+ end
72
+ operands.each_with_object({}) { |(k, v), h| h[k] = Value.new(v) }
73
+ end
74
+
75
+ sig do
76
+ params(
77
+ cpu: CPU,
78
+ opcode_definition: OpcodeDefinition,
79
+ operands: Argument::NamedValueType
80
+ ).returns(Instruction)
81
+ end
82
+ def parse(cpu, opcode_definition, operands)
83
+ parse_proc.call(cpu, opcode_definition, operands)
84
+ end
85
+ end
86
+
87
+ class OperandParser
88
+ extend T::Sig
89
+
90
+ sig { returns(String) }
91
+ attr_reader :pattern
92
+
93
+ ProcType = T.type_alias do
94
+ T.proc.params(cpu: CPU, operands: Opcode::OperandValueHashType).returns(Opcode::OperandValueHashType)
95
+ end
96
+
97
+ sig { returns(OperandParser::ProcType) }
98
+ attr_reader :parse_proc
99
+
100
+ sig { params(pattern: String, parse_proc: OperandParser::ProcType).void }
101
+ def initialize(pattern, parse_proc)
102
+ @pattern = T.let(pattern.gsub(/[^01a-zA-Z_]/, ''), String)
103
+ @parse_proc = T.let(parse_proc, OperandParser::ProcType)
104
+ end
105
+
106
+ sig { params(cpu: CPU, operands: Opcode::OperandValueHashType).returns(Opcode::OperandValueHashType) }
107
+ def parse(cpu, operands)
108
+ parse_proc.call(cpu, operands)
109
+ end
110
+ end
111
+
112
+ class DecodedOpcode
113
+ extend T::Sig
114
+
115
+ sig { returns(OpcodeDefinition) }
116
+ attr_reader :opcode_definition
117
+
118
+ sig { returns(Opcode::OperandValueHashType) }
119
+ attr_reader :operands
120
+
121
+ sig { params(opcode_definition: OpcodeDefinition, operands: Opcode::OperandValueHashType).void }
122
+ def initialize(opcode_definition, operands)
123
+ @opcode_definition = opcode_definition
124
+ @operands = operands
125
+ end
126
+
127
+ sig { params(cpu: CPU).returns(Opcode::OperandValueHashType) }
128
+ def prepare_operands(cpu)
129
+ parser = OpcodeDecoder.operand_parsers[opcode_definition.operand_pattern]
130
+ parser&.parse(cpu, operands) || operands
131
+ end
132
+ end
133
+
134
+ @opcode_definitions = T.let([], T::Array[OpcodeDefinition])
135
+ @opcode_match_masks = T.let({}, T::Hash[Integer, T::Hash[Integer, OpcodeDefinition]])
136
+ @operand_parsers = T.let({}, T::Hash[String, OpcodeDecoder::OperandParser])
137
+
138
+ class << self
139
+ extend T::Sig
140
+
141
+ sig { returns(T::Array[OpcodeDefinition]) }
142
+ attr_reader :opcode_definitions
143
+
144
+ sig { returns(T::Hash[Integer, T::Hash[Integer, OpcodeDefinition]]) }
145
+ attr_reader :opcode_match_masks
146
+
147
+ sig { returns(T::Hash[String, OpcodeDecoder::OperandParser]) }
148
+ attr_reader :operand_parsers
149
+ end
150
+
151
+ sig { params(opcode_definition: OpcodeDefinition).void }
152
+ def self.add_opcode_definition(opcode_definition)
153
+ opcode_definitions << opcode_definition
154
+ opcode_match_masks[opcode_definition.match_mask] ||= {}
155
+ opcode_match_masks.fetch(opcode_definition.match_mask)[opcode_definition.match_value] = opcode_definition
156
+ end
157
+
158
+ sig { params(operand_parser: OperandParser).void }
159
+ def self.add_operand_parser(operand_parser)
160
+ operand_parsers[operand_parser.pattern] = operand_parser
161
+ end
162
+
163
+ sig { returns(T::Hash[Integer, DecodedOpcode]) }
164
+ attr_reader :cache
165
+
166
+ sig { void }
167
+ def initialize
168
+ @cache = T.let({}, T::Hash[Integer, DecodedOpcode])
169
+ end
170
+
171
+ sig { params(word: Integer).returns(T.nilable(DecodedOpcode)) }
172
+ def decode(word)
173
+ cached_decoded_opcode = cache[word]
174
+ return cached_decoded_opcode if cached_decoded_opcode
175
+
176
+ OpcodeDecoder.opcode_match_masks.each do |mask, values|
177
+ opcode_definition = values[word & mask]
178
+ next unless opcode_definition
179
+
180
+ operands = opcode_definition.extract_operands(word)
181
+ decoded_opcode = DecodedOpcode.new(opcode_definition, operands)
182
+ cache[word] = decoded_opcode
183
+ return decoded_opcode
184
+ end
185
+ nil
186
+ end
187
+
188
+ sig { void }
189
+ def print_cache
190
+ puts "Opcode decoder cache (#{cache.size} opcodes cached):"
191
+ cache.sort.each do |word, decoded_opcode|
192
+ puts ' %04x = %17s = %-6s (%s)' % [
193
+ word,
194
+ word.to_s(2).rjust(16, '0').split('').each_slice(8).map(&:join).join(' '),
195
+ decoded_opcode.opcode_definition.mnemonic,
196
+ decoded_opcode.operands.map { |k, v| '%s = %5d' % [k, v] }.join(', '),
197
+ ]
198
+ end
199
+ nil
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,33 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Oscillator < Clock
6
+ extend T::Sig
7
+
8
+ sig { returns(T::Enumerator[TrueClass]) }
9
+ def infinite
10
+ [true].cycle
11
+ end
12
+
13
+ sig { params(time: T.any(Float, Integer)).returns(T::Enumerator[T.untyped]) }
14
+ def time_limit(time)
15
+ Enumerator.new do |y|
16
+ end_time = Time.now.to_f + time
17
+ y << true while Time.now.to_f < end_time
18
+ end
19
+ end
20
+
21
+ sig { params(limit: T::Enumerator[T.untyped]).returns(Integer) }
22
+ def run(limit = infinite)
23
+ start_ticks = ticks
24
+ limit.each { tick }
25
+ ticks - start_ticks
26
+ end
27
+
28
+ sig { params(time: T.any(Float, Integer)).returns(Integer) }
29
+ def run_timed(time)
30
+ run(time_limit(time))
31
+ end
32
+ end
33
+ end