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