avruby 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.md +28 -0
- data/README.md +17 -0
- data/bin/avruby_shell +162 -0
- data/lib/avr.rb +41 -0
- data/lib/avr/argument.rb +23 -0
- data/lib/avr/clock.rb +99 -0
- data/lib/avr/cpu.rb +254 -0
- data/lib/avr/device.rb +249 -0
- data/lib/avr/device/atmel_atmega328p.rb +181 -0
- data/lib/avr/instruction.rb +72 -0
- data/lib/avr/memory.rb +163 -0
- data/lib/avr/memory/eeprom.rb +65 -0
- data/lib/avr/memory/flash.rb +13 -0
- data/lib/avr/memory/memory_byte.rb +54 -0
- data/lib/avr/memory/sram.rb +13 -0
- data/lib/avr/opcode.rb +237 -0
- data/lib/avr/opcode/branch/conditional.rb +61 -0
- data/lib/avr/opcode/branch/return.rb +23 -0
- data/lib/avr/opcode/branch/unconditional.rb +74 -0
- data/lib/avr/opcode/break.rb +14 -0
- data/lib/avr/opcode/compare.rb +66 -0
- data/lib/avr/opcode/data/immediate.rb +14 -0
- data/lib/avr/opcode/data/program.rb +25 -0
- data/lib/avr/opcode/data/sram.rb +222 -0
- data/lib/avr/opcode/data/stack.rb +22 -0
- data/lib/avr/opcode/io/bit.rb +22 -0
- data/lib/avr/opcode/io/in_out.rb +38 -0
- data/lib/avr/opcode/math/addition.rb +120 -0
- data/lib/avr/opcode/math/bitwise.rb +170 -0
- data/lib/avr/opcode/math/multiplication.rb +23 -0
- data/lib/avr/opcode/math/subtraction.rb +137 -0
- data/lib/avr/opcode/nop.rb +14 -0
- data/lib/avr/opcode/opcodes.rb +24 -0
- data/lib/avr/opcode/operand_parsers.rb +75 -0
- data/lib/avr/opcode/register.rb +37 -0
- data/lib/avr/opcode/sleep.rb +14 -0
- data/lib/avr/opcode/sreg.rb +56 -0
- data/lib/avr/opcode/wdr.rb +14 -0
- data/lib/avr/opcode_decoder.rb +202 -0
- data/lib/avr/oscillator.rb +33 -0
- data/lib/avr/port.rb +107 -0
- data/lib/avr/register.rb +18 -0
- data/lib/avr/register/memory_byte_register.rb +27 -0
- data/lib/avr/register/memory_byte_register_with_named_bits.rb +85 -0
- data/lib/avr/register/register_file.rb +59 -0
- data/lib/avr/register/register_pair.rb +46 -0
- data/lib/avr/register/sp.rb +41 -0
- data/lib/avr/register/sreg.rb +12 -0
- data/lib/avr/register_with_bit_number.rb +40 -0
- data/lib/avr/register_with_displacement.rb +31 -0
- data/lib/avr/register_with_modification.rb +35 -0
- data/lib/avr/register_with_named_bit.rb +36 -0
- data/lib/avr/value.rb +45 -0
- data/lib/avr/version.rb +6 -0
- metadata +182 -0
data/lib/avr/device.rb
ADDED
@@ -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
|