snes_utils 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10a0fc18707cb4e615a13c7ed398cd65eb5b8f87a58ef96ad354b7448fb6ee8c
4
- data.tar.gz: 6d99ea9bfb1d5a96e4d4fbb9a9389d05999ee834cd236d9ae8ac1e9d05b65f46
3
+ metadata.gz: 7f246381ab8ed69066585483ece562451ceca114af637eae26480ae617560738
4
+ data.tar.gz: f63b5921657411c56261f4130e943c0e9cb01d6c0bd9a81ffeb32b588ee0796d
5
5
  SHA512:
6
- metadata.gz: b6b26360469e26d8af4e90abb38935a25ec1be30788331f5b051566b3a02fd834e32bf5bc14c06760cdf43a694e454215f5f6d6d0fdc6e999ba56b313d120d21
7
- data.tar.gz: b53fd68058fa91144cf7123154fa4ab1cdbdde1d7d10d5a48600b8b16d17510924e45696dabf1ab21cf92babd6e4422ced446ac8f6f0950b656e5da8dbf3e90f
6
+ metadata.gz: 133a82e1e257c37cf735b74fc9d727567b3d61d907bb51b7db5eb1f575d6bc579170dabae4abc9d9aaae9e5a2198a03c6ea65a5a504311f1750699f541b68aae
7
+ data.tar.gz: 3ffb2de928787bdd9f56ff87b1cd6b3dd45ab5c4737e54800c00d4c417a44d34d397de025d27fdfb4116ff9c0a3eac58238683b5c9431394b9dc98cfe16b67a4
@@ -6,10 +6,18 @@ require 'snes_utils'
6
6
  options = {}
7
7
  OptionParser.new do |opts|
8
8
  opts.on('-f', '--file FILENAME', 'PNG source file') { |o| options[:filename] = o }
9
+ opts.on('-b', '--bpp BPP', 'BPP') { |o| options[:bpp] = o }
10
+ opts.on('-a', '--alpha ALPHA', 'ALPHA') { |o| options[:alpha] = o }
9
11
  end.parse!
10
12
 
11
13
  raise OptionParser::MissingArgument, 'Must specify PNG source file' if options[:filename].nil?
12
14
 
13
- c = SnesUtils::Png2Snes.new options[:filename]
15
+ if options[:alpha]
16
+ alpha = options[:alpha].to_i(16)
17
+ else
18
+ alpha = nil
19
+ end
20
+
21
+ c = SnesUtils::Png2Snes.new options[:filename], bpp: options[:bpp].to_i, alpha: alpha
14
22
  c.write_palette
15
23
  c.write_image
@@ -7,11 +7,12 @@ options = {}
7
7
  OptionParser.new do |opts|
8
8
  opts.on('-f', '--file FILENAME', 'TMX source file') { |o| options[:filename] = o }
9
9
  opts.on('-s', '--tile-size TILESIZE', '8 or 16') { |o| options[:tile_size] = o.to_i }
10
+ opts.on('-p', '--palette PALETTE', 'palette no. (0..7)') { |o| options[:palette] = o.to_i }
10
11
  end.parse!
11
12
 
12
13
  raise OptionParser::MissingArgument, 'Must specify TMX source file' if options[:filename].nil?
13
14
  raise 'Wrong size : must either be 8 or 16' unless [8, 16].include? options[:tile_size]
14
15
 
15
- t = SnesUtils::Tmx2Snes.new options[:filename], big_char: options[:tile_size] == 16
16
+ t = SnesUtils::Tmx2Snes.new options[:filename], big_char: options[:tile_size] == 16, palette: options[:palette]
16
17
 
17
18
  t.write
data/bin/vas ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'snes_utils'
5
+
6
+ options = {}
7
+ OptionParser.new do |opts|
8
+ opts.on("-h", "--help", "Prints this help") do
9
+ puts opts
10
+ exit
11
+ end
12
+
13
+ opts.on('-f', '--file FILENAME', 'ASM file') { |o| options[:filename] = o }
14
+ end.parse!
15
+
16
+ SnesUtils::Vas.new(options[:filename]).assemble
@@ -1,15 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SnesUtils
2
4
  class Definitions
3
5
  HEX_DIGIT = '[0-9a-f]'
4
6
 
5
- BYTE_LOC_REGEX = /^#{HEX_DIGIT}{1,4}$/i
6
- BYTE_RANGE_REGEX = /^(#{HEX_DIGIT}{1,4})\.+(#{HEX_DIGIT}{1,4})$/i
7
- BYTE_SEQUENCE_REGEX = /^(#{HEX_DIGIT}{1,4}):\s*([0-9a-f ]+)$/i
8
- DISASSEMBLE_REGEX = /^(#{HEX_DIGIT}{,4})l/i
9
- SWITCH_BANK_REGEX = /^(#{HEX_DIGIT}{1,2})\/$/i
10
- FLIP_MX_REG_REGEX = /^([01])=([xm])$/i
11
- WRITE_REGEX = /^\.write\s*(.*)$/i
12
- INCBIN_REGEX = /^(#{HEX_DIGIT}{1,4}):\s*\.incbin\s+(.*)$/i
13
- READ_REGEX = /^((#{HEX_DIGIT}{1,4}):\s*)*\.read\s+(.*)$/i
7
+ BYTE_LOC_REGEX = /^#{HEX_DIGIT}{1,4}$/i.freeze
8
+ BYTE_RANGE_REGEX = /^(#{HEX_DIGIT}{1,4})\.+(#{HEX_DIGIT}{1,4})$/i.freeze
9
+ BYTE_SEQUENCE_REGEX = /^(#{HEX_DIGIT}{1,4}):\s*([0-9a-f ]+)$/i.freeze
10
+ READ_BYTE_SEQUENCE_REGEX = /^(.*):\s*\.db\s+([0-9a-f ]+)$/i.freeze
11
+ DISASSEMBLE_REGEX = /^(#{HEX_DIGIT}{,4})l/i.freeze
12
+ SWITCH_BANK_REGEX = %r{^(#{HEX_DIGIT}{1,2})/$}i.freeze
13
+ FLIP_MX_REG_REGEX = /^([01])=([xm])$/i.freeze
14
+ WRITE_REGEX = /^\.write\s*(.*)$/i.freeze
15
+ INCBIN_REGEX = /^(#{HEX_DIGIT}{1,4}):\s*\.incbin\s+(.*)$/i.freeze
16
+ READ_INCBIN_REGEX = /^(.*):\s*\.incbin\s+(.*)$/i.freeze
17
+ READ_INCSRC_REGEX = /^\s*\.incsrc\s+(.*)$/i.freeze
18
+ READ_REGEX = /^((#{HEX_DIGIT}{1,4}):\s*)*\.read\s+(.*)$/i.freeze
19
+ READ_BANK_SWITCH = /^\.bank\s+(#{HEX_DIGIT}{1,2})$/i.freeze
20
+ READ_ADDR_SWITCH = /^\.addr\s+(#{HEX_DIGIT}{1,4})$/i.freeze
14
21
  end
15
22
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SnesUtils
2
4
  Readline.completion_proc = proc do |input|
3
5
  Wdc65816::Definitions::OPCODES_DATA.map { |row| row[:mnemonic] }
4
- .select { |mnemonic| mnemonic.upcase.start_with?(input.upcase) }
6
+ .select { |mnemonic| mnemonic.upcase.start_with?(input.upcase) }
5
7
  end
6
8
 
7
9
  class MiniAssembler
@@ -13,7 +15,8 @@ module SnesUtils
13
15
  @memory = []
14
16
  end
15
17
 
16
- @cpu = :wdc65816
18
+ @cpu = :wdc65816 # :spc700
19
+ @mem_map = :lorom # :hirom
17
20
 
18
21
  @normal_mode = true
19
22
 
@@ -21,10 +24,9 @@ module SnesUtils
21
24
  @current_bank_no = 0
22
25
  @accumulator_flag = 1
23
26
  @index_flag = 1
27
+ @label_registry = {}
24
28
 
25
29
  @next_addr_to_list = 0
26
-
27
- @label_registry = {}
28
30
  end
29
31
 
30
32
  def run
@@ -44,7 +46,7 @@ module SnesUtils
44
46
  filename = filename.empty? ? 'out.smc' : filename
45
47
 
46
48
  File.open(filename, 'w+b') do |file|
47
- file.write([@memory.map { |i| i ? i : '00' }.join].pack('H*'))
49
+ file.write([@memory.map { |i| i || '00' }.join].pack('H*'))
48
50
  end
49
51
 
50
52
  filename
@@ -67,15 +69,14 @@ module SnesUtils
67
69
  res = read(filename)
68
70
  write(outfile)
69
71
 
70
- return res
72
+ res
71
73
  end
72
74
 
73
75
  def read(filename, start_addr = nil)
74
76
  return 0 unless File.file?(filename)
75
77
 
76
- @label_registry = {}
77
-
78
78
  current_addr = start_addr || @current_addr
79
+ current_bank_no = @current_bank_no
79
80
  instructions = []
80
81
  raw_bytes = []
81
82
  incbin_files = []
@@ -84,6 +85,8 @@ module SnesUtils
84
85
 
85
86
  2.times do |i|
86
87
  @current_addr = current_addr
88
+ @current_bank_no = current_bank_no
89
+
87
90
  instructions = []
88
91
  File.open(filename).each_with_index do |raw_line, line_no|
89
92
  line = raw_line.split(';').first.strip.chomp
@@ -95,42 +98,81 @@ module SnesUtils
95
98
  elsif line == '.65816'
96
99
  @cpu = :wdc65816
97
100
  next
101
+ elsif line == '.lorom'
102
+ @mem_map = :lorom
103
+ next
104
+ elsif line == '.hirom'
105
+ @mem_map = :hirom
106
+ next
98
107
  end
99
108
 
100
- if matches = Definitions::BYTE_SEQUENCE_REGEX.match(line)
101
- if i == 1
102
- addr = matches[1].to_i(16)
103
- bytes = matches[2].delete(' ').scan(/.{1,2}/).map { |b| hex(b.to_i(16)) }
104
- raw_bytes << [addr, bytes]
105
- end
109
+ if matches = Definitions::READ_BYTE_SEQUENCE_REGEX.match(line)
110
+ raw_addr = matches[1]
111
+ addr = if raw_addr.start_with?('%')
112
+ parse_address(line, true)
113
+ else
114
+ full_address(matches[1].to_i(16))
115
+ end
116
+ bytes = matches[2].delete(' ').scan(/.{1,2}/).map { |b| hex(b.to_i(16)) }
106
117
 
118
+ raw_bytes << [addr, bytes] if i == 1
119
+
120
+ inc_addr(@current_addr, bytes.size)
121
+ next
122
+ elsif matches = Definitions::READ_INCBIN_REGEX.match(line)
123
+ raw_addr = matches[1]
124
+ addr = if raw_addr.start_with?('%')
125
+ parse_address(line, true)
126
+ else
127
+ full_address(matches[1].to_i(16))
128
+ end
129
+ target_filename = matches[2].strip.chomp
130
+ incbin_files << [addr, target_filename] if i == 1
131
+
132
+ inc_addr(@current_addr, File.size(target_filename))
107
133
  next
108
- elsif matches = Definitions::INCBIN_REGEX.match(line)
109
- if i == 1
110
- addr = matches[1].to_i(16)
111
- filename = matches[2].strip.chomp
134
+ elsif matches = Definitions::READ_INCSRC_REGEX.match(line)
135
+ target_filename = matches[1].strip.chomp
136
+ incsrc_res = read(target_filename)
137
+ puts "incsrc: #{target_filename}, #{incsrc_res}" if i == 1
138
+ next
139
+ elsif matches = Definitions::READ_BANK_SWITCH.match(line)
140
+ new_bank_no = matches[1].to_i(16)
141
+ max_bank_no = @mem_map == :hirom ? 0x3f : 0x7f
142
+ return "Error at line #{line_no + 1}" if new_bank_no > max_bank_no
112
143
 
113
- incbin_files << [addr, filename]
114
- end
144
+ @current_bank_no = new_bank_no
145
+ @current_addr = 0
146
+
147
+ next
148
+ elsif matches = Definitions::READ_ADDR_SWITCH.match(line)
149
+ new_addr = matches[1].to_i(16)
150
+ return "Error at line #{line_no + 1}" if new_addr > 0xffff
151
+
152
+ @current_addr = new_addr
115
153
 
116
154
  next
117
155
  end
118
156
 
119
- instruction, length, address = parse_instruction(line, register_label=(i == 0), resolve_label=(i==1))
157
+ instruction, length, address = parse_instruction(line, register_label = (i == 0), resolve_label = (i == 1))
120
158
  return "Error at line #{line_no + 1}" unless instruction
121
159
 
122
- instructions << [instruction, length, address]
123
- @current_addr = address + length
160
+ instructions << [instruction, length, full_address(address)]
161
+ bank_wrap = inc_addr(address, length)
162
+ if bank_wrap && (i == 0)
163
+ puts "Warning: bank wrap at line #{line_no + 1}"
164
+ end
124
165
  end
125
166
  end
126
167
 
127
168
  @cpu = cpu
128
169
 
129
170
  total_bytes_read = 0
171
+ @current_bank_no = current_bank_no
130
172
 
131
173
  instructions.map do |instruction_arr|
132
174
  instruction, length, address = instruction_arr
133
- total_bytes_read += replace_memory_range(address, address+length-1, instruction)
175
+ total_bytes_read += replace_memory_range(address, address + length - 1, instruction)
134
176
  end
135
177
 
136
178
  raw_bytes.each do |raw_byte|
@@ -143,7 +185,22 @@ module SnesUtils
143
185
  total_bytes_read += incbin(filename, addr)
144
186
  end
145
187
 
146
- return "Read #{total_bytes_read} bytes"
188
+ dump_label_registry
189
+
190
+ "Read #{total_bytes_read} bytes"
191
+ end
192
+
193
+ def dump_label_registry
194
+ dump = ['label,snes addr,rom addr']
195
+ @label_registry.each do |k, v|
196
+ next if k.start_with?('@')
197
+
198
+ dump << "#{k},#{address_human(v[:mapped_addr], v[:mapped_bank])},#{hex(v[:rom_address], 6)}"
199
+ end
200
+
201
+ open('labels.csv', 'w') do |f|
202
+ f << dump.join("\n")
203
+ end
147
204
  end
148
205
 
149
206
  def detect_opcode_data_from_mnemonic(mnemonic, operand)
@@ -172,14 +229,26 @@ module SnesUtils
172
229
  end
173
230
  end
174
231
 
175
- def full_address(address)
176
- (@current_bank_no << 16) | address
232
+ def full_address(address, bank_no = @current_bank_no)
233
+ (bank_no << 16) | address
234
+ end
235
+
236
+ def inc_addr(address, length)
237
+ @current_addr = address + length
238
+ initial_bank_no = @current_bank_no
239
+
240
+ while @current_addr > 0xffff
241
+ @current_addr -= 0x10000
242
+ @current_bank_no += 1
243
+ end
244
+
245
+ @current_bank_no != initial_bank_no
177
246
  end
178
247
 
179
- def address_human(addr=nil)
180
- address = full_address(addr || @current_addr)
248
+ def address_human(addr = nil, cur_bank = @current_bank_no)
249
+ address = full_address(addr || @current_addr, cur_bank)
181
250
  bank = address >> 16
182
- addr = (((address>>8)&0xFF) << 8) | (address&0xFF)
251
+ addr = (((address >> 8) & 0xFF) << 8) | (address & 0xFF)
183
252
  "#{hex(bank)}/#{hex(addr, 4)}"
184
253
  end
185
254
 
@@ -191,7 +260,9 @@ module SnesUtils
191
260
  start_full_addr = full_address(start_addr)
192
261
  end_full_addr = full_address(end_addr)
193
262
 
194
- return [] if start_full_addr > end_full_addr || start_full_addr >= @memory.length
263
+ if start_full_addr > end_full_addr || start_full_addr >= @memory.length
264
+ return []
265
+ end
195
266
 
196
267
  @memory[start_full_addr..end_full_addr]
197
268
  end
@@ -214,62 +285,62 @@ module SnesUtils
214
285
  if @normal_mode
215
286
  if line == '!'
216
287
  @normal_mode = false
217
- return
288
+ nil
218
289
  elsif line == '.spc700'
219
290
  @cpu = :spc700
220
- return 'spc700'
291
+ 'spc700'
221
292
  elsif line == '.65816'
222
293
  @cpu = :wdc65816
223
- return '65816'
294
+ '65816'
224
295
  elsif matches = Definitions::WRITE_REGEX.match(line)
225
296
  filename = matches[1].strip.chomp
226
297
  out_filename = write(filename)
227
- return "Written #{@memory.size} bytes to file #{out_filename}"
298
+ "Written #{@memory.size} bytes to file #{out_filename}"
228
299
  elsif matches = Definitions::READ_REGEX.match(line)
229
300
  start_addr = matches[2]&.to_i(16)
230
301
  filename = matches[3].strip.chomp
231
302
 
232
- return read(filename, start_addr)
303
+ read(filename, start_addr)
233
304
  elsif matches = Definitions::INCBIN_REGEX.match(line)
234
305
  start_addr = matches[1].to_i(16)
235
306
  filename = matches[2].strip.chomp
236
307
  nb_bytes = incbin(filename, start_addr)
237
308
 
238
- return "Inserted #{nb_bytes} bytes at #{address_human(start_addr)}"
309
+ "Inserted #{nb_bytes} bytes at #{address_human(start_addr)}"
239
310
  elsif Definitions::BYTE_LOC_REGEX =~ line
240
- return memory_loc(line.to_i(16))
311
+ memory_loc(line.to_i(16))
241
312
  elsif matches = Definitions::BYTE_RANGE_REGEX.match(line)
242
313
  start_addr = matches[1].to_i(16)
243
314
  end_addr = matches[2].to_i(16)
244
315
 
245
316
  padding_count = start_addr % 8
246
- padding = (1..padding_count).map { |b| ' ' }
317
+ padding = (1..padding_count).map { |_b| ' ' }
247
318
  arr = memory_range(start_addr, end_addr)
248
319
  return if arr.empty?
249
320
 
250
- padded_arr = arr.insert(8-padding_count, *padding).each_slice(8).to_a
251
- return padded_arr.each_with_index.map do |row, idx|
252
- if idx == 0
253
- line_addr = start_addr
254
- else
255
- line_addr = start_addr - padding_count + idx * 8
256
- end
321
+ padded_arr = arr.insert(8 - padding_count, *padding).each_slice(8).to_a
322
+ padded_arr.each_with_index.map do |row, idx|
323
+ line_addr = if idx == 0
324
+ start_addr
325
+ else
326
+ start_addr - padding_count + idx * 8
327
+ end
257
328
  ["#{address_human(line_addr)}-", *row].join(' ')
258
329
  end.join("\n")
259
330
  elsif matches = Definitions::BYTE_SEQUENCE_REGEX.match(line)
260
331
  addr = matches[1].to_i(16)
261
332
  bytes = matches[2].delete(' ').scan(/.{1,2}/).map { |b| hex(b.to_i(16)) }
262
333
  replace_memory_range(addr, addr + bytes.length - 1, bytes)
263
- return
334
+ nil
264
335
  elsif matches = Definitions::DISASSEMBLE_REGEX.match(line)
265
336
  start = matches[1].empty? ? @next_addr_to_list : matches[1].to_i(16)
266
- return disassemble_range(start, 20).join("\n")
337
+ disassemble_range(start, 20).join("\n")
267
338
  elsif matches = Definitions::SWITCH_BANK_REGEX.match(line)
268
339
  target_bank_no = matches[1].to_i(16)
269
340
  @current_bank_no = target_bank_no
270
341
  @current_addr = @current_bank_no << 16
271
342
  @next_addr_to_list = 0
272
- return
343
+ nil
273
344
  elsif matches = Definitions::FLIP_MX_REG_REGEX.match(line)
274
345
  val = matches[1]
275
346
  reg = matches[2]
@@ -280,59 +351,132 @@ module SnesUtils
280
351
  @index_flag = val.to_i
281
352
  end
282
353
 
283
- return
354
+ nil
284
355
  end
285
356
  else
286
357
  if line == ''
287
358
  @normal_mode = true
288
- return
359
+ nil
289
360
  else
290
361
  instruction, length, address = parse_instruction(line)
291
362
  return 'error' unless instruction
292
363
 
293
- replace_memory_range(address, address+length-1, instruction)
294
- @current_addr = address + length
295
- return disassemble_range(address, 1, length > 2).join
364
+ replace_memory_range(address, address + length - 1, instruction)
365
+ inc_addr(address, length)
366
+ disassemble_range(address, 1, length > 2).join
296
367
  end
297
368
  end
298
369
  end
299
370
 
300
- def parse_address(line, register_label = false)
371
+ def mapped_address(address, absolute = false)
372
+ return hex(address, 4) unless absolute
373
+
374
+ if @mem_map == :lorom
375
+ bank_offset = address / 0x8000
376
+ mapped_addr = address - (bank_offset * 0x8000)
377
+ mapped_addr += 0x8000 if mapped_addr < 0x8000
378
+ mapped_bank = @current_bank_no * 2
379
+ mapped_bank += bank_offset
380
+ mapped_bank += 0x80 if mapped_bank < 0x7f
381
+
382
+ { mapped_bank: mapped_bank, mapped_addr: mapped_addr, rom_address: full_address(address) }
383
+ elsif @mem_map == :hirom
384
+ mapped_bank = @current_bank_no + 0xc0 if @current_bank_no < 0x3f
385
+ { mapped_bank: mapped_bank, mapped_addr: address, rom_address: full_address(address) }
386
+ else
387
+ {}
388
+ end
389
+ end
390
+
391
+ def detect_label_type(address)
392
+ address = address[1..-1] if address.start_with?('#')
393
+ if address.start_with?('@')
394
+ :relative
395
+ elsif address.start_with?('%')
396
+ :absolute16
397
+ elsif address.start_with?('&')
398
+ :absolute24
399
+ end
400
+ end
401
+
402
+ def contains_label?(op)
403
+ op.include?('@') | op.include?('%') | op.include?('&')
404
+ end
405
+
406
+ def parse_address(line, _register_label = false)
301
407
  return @current_addr if line.index(':').nil?
302
408
 
303
409
  address = line.split(':').first.strip.chomp
304
- return address.to_i(16) unless address.start_with?('@')
410
+ return -1 if address.to_i(16) > 0xffff
411
+ return address.to_i(16) if detect_label_type(address).nil?
412
+
413
+ label_type = detect_label_type(address)
414
+ case label_type
415
+ when :relative
416
+ @label_registry[address] = mapped_address(@current_addr)
417
+ when :absolute16
418
+ @label_registry[address[1..-1]] = mapped_address(@current_addr, true)
419
+ when :absolute24
420
+ @label_registry[address[1..-1]] = mapped_address(@current_addr, true)
421
+ else
422
+ op
423
+ end
305
424
 
306
- @label_registry[address] = hex(@current_addr, 4)
307
- return @current_addr
425
+ @current_addr
308
426
  end
309
427
 
310
428
  def parse_instruction(line, register_label = false, resolve_label = false)
311
429
  current_address = parse_address(line, register_label)
430
+ return if current_address < 0 || current_address > 0xffff
431
+
312
432
  instruction = line.split(':').last.split(' ')
313
433
  mnemonic = instruction[0].upcase
314
434
  raw_operand = instruction[1].to_s
315
435
 
316
- if register_label and raw_operand.include?('@')
317
- raw_operands = raw_operand.split(',')
318
- raw_operands.each_with_index do |op, idx|
319
- if op.start_with?('@')
320
- raw_operands[idx] = hex(@current_addr, 4)
436
+ if register_label && contains_label?(raw_operand)
437
+ raw_operand = raw_operand.split(',').map do |op|
438
+ label_type = detect_label_type(op)
439
+ case label_type
440
+ when :relative
441
+ mapped_address(@current_addr)
442
+ when :absolute16
443
+ dummy = mapped_address(@current_addr, true)
444
+ dummy[:mapped_addr].to_s(16)
445
+ when :absolute24
446
+ dummy = mapped_address(@current_addr, true)
447
+ full_address(dummy[:mapped_addr], dummy[:mapped_bank]).to_s(16)
448
+ else
449
+ op
321
450
  end
322
- end
323
-
324
- raw_operand = raw_operands.join(',')
451
+ end.join(',')
325
452
  end
326
453
 
327
- if resolve_label and raw_operand.include?('@')
328
- raw_operands = raw_operand.split(',')
329
- raw_operands.each_with_index do |op, idx|
330
- if op.start_with?('@')
331
- raw_operands[idx] = @label_registry[op]
454
+ if resolve_label && contains_label?(raw_operand)
455
+ raw_operand = raw_operand.split(',').map do |op|
456
+ label_type = detect_label_type(op)
457
+ case label_type
458
+ when :relative
459
+ if op.start_with?('#')
460
+ @label_registry[op[1..-1]]
461
+ else
462
+ @label_registry[op]
463
+ end
464
+ when :absolute16
465
+ if op.start_with?('#')
466
+ "##{@label_registry[op[2..-1]][:mapped_addr].to_s(16)}"
467
+ else
468
+ @label_registry[op[1..-1]][:mapped_addr].to_s(16)
469
+ end
470
+ when :absolute24
471
+ if op.start_with?('#')
472
+ "##{full_address(@label_registry[op[2..-1]][:mapped_addr], @label_registry[op[1..-1]][:mapped_bank]).to_s(16)}"
473
+ else
474
+ full_address(@label_registry[op[1..-1]][:mapped_addr], @label_registry[op[1..-1]][:mapped_bank]).to_s(16)
475
+ end
476
+ else
477
+ op
332
478
  end
333
- end
334
-
335
- raw_operand = raw_operands.join(',')
479
+ end.join(',')
336
480
  end
337
481
 
338
482
  opcode_data = detect_opcode_data_from_mnemonic(mnemonic, raw_operand)
@@ -349,10 +493,11 @@ module SnesUtils
349
493
  if SnesUtils.const_get(@cpu.capitalize)::Definitions::BIT_INSTRUCTIONS.include?(mode)
350
494
  m = operand_matches[1].to_i(16)
351
495
  return if m > 0x1fff
496
+
352
497
  b = operand_matches[2].to_i(16)
353
498
  return if b > 7
354
499
 
355
- operand = m << 3 | 5
500
+ operand = m << 3 | b
356
501
  else
357
502
  if SnesUtils.const_get(@cpu.capitalize)::Definitions::REL_INSTRUCTIONS.include?(mode)
358
503
  operand = [operand_matches[1], operand_matches[2]].map { |o| o.to_i(16) }
@@ -369,7 +514,7 @@ module SnesUtils
369
514
  if SnesUtils.const_get(@cpu.capitalize)::Definitions::DOUBLE_OPERAND_INSTRUCTIONS.include?(mode)
370
515
  relative_addr = operand[1] - current_address - length
371
516
 
372
- return if (relative_addr < -128 || relative_addr > 127)
517
+ return if relative_addr < -128 || relative_addr > 127
373
518
 
374
519
  relative_addr = 0x100 + relative_addr if relative_addr < 0
375
520
  param_bytes = "#{hex(operand[0])}#{hex(relative_addr)}"
@@ -377,29 +522,31 @@ module SnesUtils
377
522
  relative_addr = operand - current_address - length
378
523
 
379
524
  if @cpu == :wdc65816 && mode == :rell
380
- return if (relative_addr < -32768 || relative_addr > 32767)
525
+ return if relative_addr < -32_768 || relative_addr > 32_767
381
526
  else
382
- return if (relative_addr < -128 || relative_addr > 127)
527
+ return if relative_addr < -128 || relative_addr > 127
383
528
  end
384
529
 
385
- relative_addr = (2**(8*(length-1))) + relative_addr if relative_addr < 0
386
- param_bytes = hex(relative_addr, 2*(length-1)).scan(/.{2}/).reverse.join
530
+ if relative_addr < 0
531
+ relative_addr = (2**(8 * (length - 1))) + relative_addr
532
+ end
533
+ param_bytes = hex(relative_addr, 2 * (length - 1)).scan(/.{2}/).reverse.join
387
534
  end
388
535
  else
389
- param_bytes = hex(operand, 2*(length-1)).scan(/.{2}/).reverse.join
536
+ param_bytes = hex(operand, 2 * (length - 1)).scan(/.{2}/).reverse.join
390
537
  end
391
538
  end
392
539
 
393
540
  encoded_result = "#{opcode}#{param_bytes}"
394
541
 
395
- return [encoded_result.scan(/.{2}/), length, current_address]
542
+ [encoded_result.scan(/.{2}/), length, current_address]
396
543
  end
397
544
 
398
545
  def auto_update_flags(opcode, operand)
399
- if 0xc2 == opcode
546
+ if opcode == 0xc2
400
547
  @index_flag = 0 if (operand & 0x10) == 0x10
401
548
  @accumulator_flag = 0 if (operand & 0x20) == 0x20
402
- elsif 0xe2 == opcode
549
+ elsif opcode == 0xe2
403
550
  @index_flag = 1 if (operand & 0x10) == 0x10
404
551
  @accumulator_flag = 1 if (operand & 0x20) == 0x20
405
552
  end
@@ -411,6 +558,7 @@ module SnesUtils
411
558
  count.times do
412
559
  byte = memory_loc(next_idx)
413
560
  break unless byte
561
+
414
562
  opcode = byte.to_i(16)
415
563
 
416
564
  opcode_data = detect_opcode_data_from_opcode(opcode, force_length)
@@ -421,9 +569,9 @@ module SnesUtils
421
569
 
422
570
  format = SnesUtils.const_get(@cpu.capitalize)::Definitions::MODES_FORMATS[mode]
423
571
 
424
- operand = memory_range(next_idx+1, next_idx+length-1).reverse.join.to_i(16)
572
+ operand = memory_range(next_idx + 1, next_idx + length - 1).reverse.join.to_i(16)
425
573
 
426
- hex_encoded_instruction = memory_range(next_idx, next_idx+length-1)
574
+ hex_encoded_instruction = memory_range(next_idx, next_idx + length - 1)
427
575
  prefix = ["#{address_human(next_idx)}:", *hex_encoded_instruction].join(' ')
428
576
 
429
577
  auto_update_flags(opcode, operand) if @cpu == :wdc65816
@@ -455,12 +603,12 @@ module SnesUtils
455
603
  end
456
604
  end
457
605
 
458
- instructions << "#{prefix.ljust(30)} #{format % [mnemonic, *operand]}"
606
+ instructions << "#{prefix.ljust(30)} #{format(format, mnemonic, *operand)}"
459
607
  next_idx += length
460
608
  end
461
609
 
462
610
  @next_addr_to_list = next_idx
463
- return instructions
611
+ instructions
464
612
  end
465
613
 
466
614
  def relative_operand(operand, next_idx, limit = 0x7f, offset = 0x100, rjust_len = 2)