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,249 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Device
6
+ extend T::Sig
7
+ extend T::Helpers
8
+ abstract!
9
+
10
+ sig { abstract.returns(Integer) }
11
+ def sram_size; end
12
+
13
+ sig { abstract.returns(Integer) }
14
+ def flash_size; end
15
+
16
+ sig { abstract.returns(Integer) }
17
+ def eeprom_size; end
18
+
19
+ sig { abstract.returns(T::Hash[Symbol, Integer]) }
20
+ def data_memory_map; end
21
+
22
+ sig { abstract.returns(Integer) }
23
+ def register_start; end
24
+
25
+ sig { abstract.returns(Integer) }
26
+ def register_count; end
27
+
28
+ sig { abstract.returns(T::Hash[Symbol, T::Array[T.nilable(Symbol)]]) }
29
+ def register_bit_names_map; end
30
+
31
+ sig { abstract.returns(T::Hash[Symbol, T::Hash[Symbol, Integer]]) }
32
+ def word_register_map; end
33
+
34
+ sig { abstract.returns(Integer) }
35
+ def io_register_start; end
36
+
37
+ sig { abstract.returns(Integer) }
38
+ def io_register_count; end
39
+
40
+ sig { abstract.returns(Integer) }
41
+ def ext_io_register_start; end
42
+
43
+ sig { abstract.returns(Integer) }
44
+ def ext_io_register_count; end
45
+
46
+ sig { abstract.returns(Integer) }
47
+ def ram_start; end
48
+
49
+ sig { abstract.returns(Integer) }
50
+ def ram_end; end
51
+
52
+ sig { abstract.returns(T::Hash[Symbol, Integer]) }
53
+ def interrupt_vector_map; end
54
+
55
+ sig { abstract.returns(T::Hash[Symbol, T::Hash[Symbol, Integer]]) }
56
+ def port_map; end
57
+
58
+ sig { returns(T::Hash[Integer, Symbol]) }
59
+ def data_memory_map_by_address
60
+ @data_memory_map_by_address ||= data_memory_map.each_with_object({}) do |(n, a), h|
61
+ h[a] = n unless n =~ /^_/
62
+ end
63
+ end
64
+
65
+ sig { returns(T::Array[T.nilable(Symbol)]) }
66
+ def io_registers
67
+ @io_registers ||= (0...io_register_count).map do |i|
68
+ data_memory_map_by_address[io_register_start + i]
69
+ end
70
+ end
71
+
72
+ sig { params(port: T.any(Symbol, String)).returns(T::Hash[Symbol, Integer]) }
73
+ def standard_port(port)
74
+ {
75
+ pin: data_memory_map["PIN#{port}".to_sym],
76
+ ddr: data_memory_map["DDR#{port}".to_sym],
77
+ port: data_memory_map["PORT#{port}".to_sym],
78
+ }
79
+ end
80
+
81
+ sig do
82
+ params(
83
+ ports: T::Array[T.any(Symbol, String)]
84
+ ).returns(T::Hash[Symbol, T::Hash[Symbol, Integer]])
85
+ end
86
+ def standard_ports(ports)
87
+ ports.each_with_object({}) { |m, h| h[m] = standard_port(m) }
88
+ end
89
+
90
+ sig { params(interrupts: T::Array[T.any(Symbol, String)]).returns(T::Hash[Symbol, Integer]) }
91
+ def sequential_interrupt_vectors(interrupts)
92
+ interrupts.each_with_index.each_with_object({}) { |(name, i), h| h[name.to_sym] = i * 2 }
93
+ end
94
+
95
+ sig { returns(CPU) }
96
+ attr_reader :cpu
97
+
98
+ sig { returns(Clock) }
99
+ attr_reader :system_clock
100
+
101
+ sig { returns(Oscillator) }
102
+ attr_reader :oscillator
103
+
104
+ sig { returns(Flash) }
105
+ attr_reader :flash
106
+
107
+ sig { returns(EEPROM) }
108
+ attr_reader :eeprom
109
+
110
+ sig { void }
111
+ def initialize
112
+ @cpu = T.let(CPU.new(self), CPU)
113
+ @flash = T.let(Flash.new(flash_size), Flash)
114
+ @eeprom = T.let(EEPROM.new(eeprom_size, cpu), EEPROM)
115
+
116
+ @system_clock = T.let(Clock.new('system'), Clock)
117
+ @system_clock.push_sink(cpu.clock)
118
+
119
+ @oscillator = T.let(Oscillator.new('oscillator'), Oscillator)
120
+ @oscillator.push_sink(system_clock)
121
+
122
+ @data_memory_map_by_address = T.let(nil, T.nilable(T::Hash[Integer, Symbol]))
123
+ @io_registers = T.let(nil, T.nilable(T::Array[T.nilable(Symbol)]))
124
+ end
125
+
126
+ sig { void }
127
+ def trace_cpu
128
+ cpu.trace do |instruction|
129
+ puts '*** %20s: %s' % [
130
+ 'INSTRUCTION TRACE',
131
+ instruction,
132
+ ]
133
+ end
134
+ end
135
+
136
+ sig { void }
137
+ def trace_registers
138
+ register_addresses = {}
139
+ cpu.registers.registers.each do |_name, register|
140
+ case register
141
+ when MemoryByteRegister
142
+ register_addresses[register.memory_byte.address] ||= []
143
+ register_addresses[register.memory_byte.address] << register
144
+ when RegisterPair
145
+ register_addresses[register.l.memory_byte.address] ||= []
146
+ register_addresses[register.l.memory_byte.address] << register
147
+ register_addresses[register.h.memory_byte.address] ||= []
148
+ register_addresses[register.h.memory_byte.address] << register
149
+ end
150
+ end
151
+ cpu.sram.watch do |memory_byte, old_value, _new_value|
152
+ registers = register_addresses[memory_byte.address]
153
+ registers&.each do |register|
154
+ puts '*** %20s: %12s: %4s -> %4s' % [
155
+ 'REGISTER TRACE',
156
+ register.name,
157
+ register.is_a?(MemoryByteRegister) ? register.format % old_value : '',
158
+ register.format % register.value,
159
+ ]
160
+ end
161
+ end
162
+ end
163
+
164
+ sig { void }
165
+ def trace_sreg
166
+ cpu.sram.watch do |memory_byte, old_value, new_value|
167
+ if memory_byte.address == cpu.sreg.memory_byte.address
168
+ puts '*** %20s: %s' % [
169
+ 'SREG TRACE',
170
+ cpu.sreg.diff_values(old_value, new_value),
171
+ ]
172
+ end
173
+ end
174
+ end
175
+
176
+ sig { void }
177
+ def trace_sram
178
+ cpu.sram.watch do |memory_byte, old_value, new_value|
179
+ puts '*** %20s: %12s: %4s -> %4s' % [
180
+ 'MEMORY TRACE',
181
+ '%s[%04x]' % [memory_byte.memory.name, memory_byte.address],
182
+ memory_byte.format % old_value,
183
+ memory_byte.format % new_value,
184
+ ]
185
+ end
186
+ end
187
+
188
+ sig { void }
189
+ def trace_flash
190
+ flash.watch do |memory_byte, old_value, new_value|
191
+ puts '*** %20s: %12s: %4s -> %4s' % [
192
+ 'MEMORY TRACE',
193
+ '%s[%04x]' % [memory_byte.memory.name, memory_byte.address],
194
+ memory_byte.format % old_value,
195
+ memory_byte.format % new_value,
196
+ ]
197
+ end
198
+ end
199
+
200
+ sig { void }
201
+ def trace_eeprom
202
+ eeprom.watch do |memory_byte, old_value, new_value|
203
+ puts '*** %20s: %12s: %4s -> %4s' % [
204
+ 'MEMORY TRACE',
205
+ '%s[%04x]' % [memory_byte.memory.name, memory_byte.address],
206
+ memory_byte.format % old_value,
207
+ memory_byte.format % new_value,
208
+ ]
209
+ end
210
+ end
211
+
212
+ sig { void }
213
+ def trace_status_pre_tick
214
+ oscillator.unshift_sink(
215
+ Clock::Sink.new('pre-execution status') do
216
+ puts
217
+ puts
218
+ puts 'PRE-EXECUTION STATUS'
219
+ puts '********************'
220
+ cpu.print_status
221
+ end
222
+ )
223
+ end
224
+
225
+ sig { void }
226
+ def trace_status_post_tick
227
+ oscillator.push_sink(
228
+ Clock::Sink.new('post-execution status') do
229
+ puts
230
+ puts 'POST-EXECUTION STATUS'
231
+ puts '*********************'
232
+ cpu.print_status
233
+ end
234
+ )
235
+ end
236
+
237
+ sig { void }
238
+ def trace_all
239
+ trace_cpu
240
+ trace_sram
241
+ trace_flash
242
+ trace_eeprom
243
+ trace_sreg
244
+ trace_registers
245
+ trace_status_pre_tick
246
+ trace_status_post_tick
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,181 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Device
6
+ class Atmel_ATmega328p < Device # rubocop:disable Naming/ClassAndModuleCamelCase
7
+ extend T::Sig
8
+
9
+ sig { void }
10
+ def initialize
11
+ super
12
+
13
+ # Type annotations for variables used in memoization.
14
+ @register_bit_names_map = T.let(nil, T.nilable(T::Hash[Symbol, T::Array[T.nilable(Symbol)]]))
15
+ @word_register_map = T.let(nil, T.nilable(T::Hash[Symbol, T::Hash[Symbol, Integer]]))
16
+ @data_memory_map = T.let(nil, T.nilable(T::Hash[Symbol, Integer]))
17
+ @interrupt_vector_map = T.let(nil, T.nilable(T::Hash[Symbol, Integer]))
18
+ @port_map = T.let(nil, T.nilable(T::Hash[Symbol, T::Hash[Symbol, Integer]]))
19
+ end
20
+
21
+ sig { override.returns(Integer) }
22
+ def sram_size
23
+ 2048
24
+ end
25
+
26
+ sig { override.returns(Integer) }
27
+ def flash_size
28
+ 32_768
29
+ end
30
+
31
+ sig { override.returns(Integer) }
32
+ def eeprom_size
33
+ 512
34
+ end
35
+
36
+ sig { override.returns(T::Hash[Symbol, T::Hash[Symbol, Integer]]) }
37
+ def word_register_map
38
+ @word_register_map ||= {
39
+ X: { l: 26, h: 27 },
40
+ Y: { l: 28, h: 29 },
41
+ Z: { l: 30, h: 31 },
42
+ }
43
+ end
44
+
45
+ sig { override.returns(T::Hash[Symbol, Integer]) }
46
+ def data_memory_map
47
+ # rubocop:disable Layout/HashAlignment
48
+ @data_memory_map ||= {
49
+ # 32 registers, r0-r31
50
+ PINB: 0x0023,
51
+ DDRB: 0x0024,
52
+ PORTB: 0x0025,
53
+ PINC: 0x0026,
54
+ DDRC: 0x0027,
55
+ PORTC: 0x0028,
56
+ PIND: 0x0029,
57
+ DDRD: 0x002a,
58
+ PORTD: 0x002b,
59
+ TIFR0: 0x0035,
60
+ TIFR1: 0x0035,
61
+ TIFR2: 0x0035,
62
+ PCIFR: 0x003b,
63
+ EIFR: 0x003c,
64
+ EIMSK: 0x003d,
65
+ GPIOR0: 0x003e,
66
+ EECR: 0x003f,
67
+ EEDR: 0x0040,
68
+ EEARL: 0x0041,
69
+ EEARH: 0x0042,
70
+ GTCCR: 0x0043,
71
+ TCCR0A: 0x0044,
72
+ TCCR0B: 0x0045,
73
+ TCNT0: 0x0046,
74
+ OCR0A: 0x0047,
75
+ OCR0B: 0x0048,
76
+ GPIOR1: 0x004a,
77
+ GPIOR2: 0x004b,
78
+ SPCR: 0x004c,
79
+ SPSR: 0x004d,
80
+ SPDR: 0x004e,
81
+ ACSR: 0x0050,
82
+ SMCR: 0x0053,
83
+ MCUSR: 0x0054,
84
+ MCUCR: 0x0055,
85
+ SPMCSR: 0x0057,
86
+ SPL: 0x005d,
87
+ SPH: 0x005e,
88
+ SREG: 0x005f,
89
+ EICRA: 0x0069,
90
+ }.freeze
91
+ # rubocop:enable Layout/HashAlignment
92
+ end
93
+
94
+ sig { override.returns(T::Hash[Symbol, T::Array[T.nilable(Symbol)]]) }
95
+ def register_bit_names_map
96
+ @register_bit_names_map ||= {
97
+ EECR: [:EERE, :EEPE, :EEMPE, :EERIE, :EEPM0, :EEPM1, nil, nil],
98
+ }
99
+ end
100
+
101
+ sig { override.returns(Integer) }
102
+ def register_start
103
+ 0x0000
104
+ end
105
+
106
+ sig { override.returns(Integer) }
107
+ def register_count
108
+ 32
109
+ end
110
+
111
+ sig { override.returns(Integer) }
112
+ def io_register_start
113
+ 0x0020
114
+ end
115
+
116
+ sig { override.returns(Integer) }
117
+ def io_register_count
118
+ 64
119
+ end
120
+
121
+ sig { override.returns(Integer) }
122
+ def ext_io_register_start
123
+ 0x0060
124
+ end
125
+
126
+ sig { override.returns(Integer) }
127
+ def ext_io_register_count
128
+ 160
129
+ end
130
+
131
+ sig { override.returns(Integer) }
132
+ def ram_start
133
+ 0x0100
134
+ end
135
+
136
+ sig { override.returns(Integer) }
137
+ def ram_end
138
+ ram_start + sram_size - 1
139
+ end
140
+
141
+ sig { override.returns(T::Hash[Symbol, Integer]) }
142
+ def interrupt_vector_map
143
+ @interrupt_vector_map ||= sequential_interrupt_vectors(
144
+ %i[
145
+ RESET
146
+ INT0
147
+ INT1
148
+ PCINT0
149
+ PCINT1
150
+ PCINT2
151
+ WDT
152
+ TIMER2_COMPA
153
+ TIMER2_COMPB
154
+ TIMER2_OVF
155
+ TIMER1_CAPT
156
+ TIMER1_COMPA
157
+ TIMER1_COMPB
158
+ TIMER1_OVF
159
+ TIMER0_COMPA
160
+ TIMER0_COMPB
161
+ TIMER0_OVF
162
+ SPI_STC
163
+ USART_RX
164
+ USART_UDRE
165
+ USART_TX
166
+ ADC
167
+ EE_READY
168
+ ANALOG_COMP
169
+ TWI
170
+ SPM_READY
171
+ ]
172
+ )
173
+ end
174
+
175
+ sig { override.returns(T::Hash[Symbol, T::Hash[Symbol, Integer]]) }
176
+ def port_map
177
+ @port_map ||= standard_ports(%i[B C D])
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,72 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AVR
5
+ class Instruction
6
+ extend T::Sig
7
+
8
+ sig { returns(CPU) }
9
+ attr_reader :cpu
10
+
11
+ sig { returns(Symbol) }
12
+ attr_reader :mnemonic
13
+
14
+ sig { returns(Argument::ArrayType) }
15
+ attr_reader :args
16
+
17
+ sig { returns(Opcode) }
18
+ attr_reader :opcode
19
+
20
+ sig { params(cpu: CPU, mnemonic: Symbol, args: Argument::ArrayType).void }
21
+ def initialize(cpu, mnemonic, args)
22
+ raise "Unknown opcode #{mnemonic}" unless Opcode.opcodes.include?(mnemonic)
23
+
24
+ @cpu = cpu
25
+ @mnemonic = mnemonic
26
+ @args = args
27
+ @opcode = T.let(Opcode.opcodes.fetch(mnemonic), Opcode)
28
+ end
29
+
30
+ sig { returns(T::Boolean) }
31
+ def validate
32
+ opcode.validate(args)
33
+ end
34
+
35
+ sig { returns(T::Boolean) }
36
+ def valid?
37
+ validate
38
+ true
39
+ end
40
+
41
+ sig { returns(T.nilable(String)) }
42
+ def args_to_s
43
+ #return args.join(', ') unless opcode
44
+ return nil if opcode.arg_types.empty?
45
+
46
+ opcode.format_args(args).join(', ')
47
+ end
48
+
49
+ sig { returns(String) }
50
+ def to_s
51
+ return mnemonic.to_s if args.empty?
52
+
53
+ "#{mnemonic} #{args_to_s}"
54
+ end
55
+
56
+ sig { returns(String) }
57
+ def inspect
58
+ "#<#{self.class.name} {#{self}}>"
59
+ end
60
+
61
+ sig { void }
62
+ def execute
63
+ raise 'Invalid instruction' unless valid?
64
+
65
+ cpu.next_pc = cpu.pc + 1
66
+ opcode.execute(cpu, nil, args)
67
+ cpu.pc = cpu.next_pc
68
+
69
+ nil
70
+ end
71
+ end
72
+ end