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