snes_utils 0.1.1 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10a0fc18707cb4e615a13c7ed398cd65eb5b8f87a58ef96ad354b7448fb6ee8c
4
- data.tar.gz: 6d99ea9bfb1d5a96e4d4fbb9a9389d05999ee834cd236d9ae8ac1e9d05b65f46
3
+ metadata.gz: 9bce5ff7aea0b674c5c19db5c83979f66b4993e9b0de36a19c432cc7bcb09745
4
+ data.tar.gz: 78b040ccc9a686496535c135e3908ab63bfcd9c2c4fece2761a77f5588f49a9d
5
5
  SHA512:
6
- metadata.gz: b6b26360469e26d8af4e90abb38935a25ec1be30788331f5b051566b3a02fd834e32bf5bc14c06760cdf43a694e454215f5f6d6d0fdc6e999ba56b313d120d21
7
- data.tar.gz: b53fd68058fa91144cf7123154fa4ab1cdbdde1d7d10d5a48600b8b16d17510924e45696dabf1ab21cf92babd6e4422ced446ac8f6f0950b656e5da8dbf3e90f
6
+ metadata.gz: dfd37be40699f3a075c5b5c1e1779bb8fe4aed85da84d1f64be3a325d427416c070df8677d3f054d63edc63339080c467211feb903006878726fc8d66c84fee8
7
+ data.tar.gz: 44d97b051f1b75b94e3f823ec41efdbd08100a24674fb0255e3e40130bf2418506b6bd31035813ae31ff0253c2874155ed5fa40caf10806bd21ff4f745f32e4d
data/bin/png2snes CHANGED
@@ -6,10 +6,29 @@ 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 }
11
+ opts.on('-m', '--mode7', 'mode 7') { |o| options[:mode7] = o }
12
+ opts.on('-o', '--offset OFFSET', 'mode 7 palette offset') { |o| options[:m7_palette_offset] = o }
9
13
  end.parse!
10
14
 
11
15
  raise OptionParser::MissingArgument, 'Must specify PNG source file' if options[:filename].nil?
12
16
 
13
- c = SnesUtils::Png2Snes.new options[:filename]
17
+ if options[:alpha]
18
+ alpha = options[:alpha].to_i(16)
19
+ else
20
+ alpha = nil
21
+ end
22
+
23
+ if options[:m7_palette_offset]
24
+ m7_palette_offset = options[:m7_palette_offset].to_i
25
+ else
26
+ m7_palette_offset = nil
27
+ end
28
+
29
+ c = SnesUtils::Png2Snes.new(options[:filename], bpp: options[:bpp].to_i,
30
+ alpha: alpha,
31
+ mode7: options[:mode7],
32
+ m7_palette_offset: m7_palette_offset)
14
33
  c.write_palette
15
34
  c.write_image
data/bin/tmx2snes CHANGED
@@ -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,17 @@
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
+ opts.on("-o", "--out FILENAME", "output file") { |o| options[:outfile] = o }
15
+ end.parse!
16
+
17
+ SnesUtils::Vas.new(options[:filename], options[:outfile]).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)