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